
A Fresh Look at Rust - boynamedsue
http://lucumr.pocoo.org/2014/10/1/a-fresh-look-at-rust/
======
ekidd
I've been using Rust to process a large text corpus, and as Armin suggests,
it's a really interesting experience. Here are a few things I've noticed so
far:

1\. Writing Rust code definitely takes more time than Python or Ruby, but it's
not bad in practice. I can't measure the productivity difference yet, partly
because I'm still learning Rust. I do spend more time thinking about how to
write zero-allocation and zero-copy algorithms, and trying to get my code to
compile (but see 3, below).

2\. It's possible to write very fast code without compromising memory safety.
It's great to see key parsing operations happening in ~100 nanoseconds, with
no allocations.

3\. Rust is one of those languages where I need to work to make the compiler
happy, but once I manage that, the code generally works on the first try.

4\. The tooling is very good: library management, unit testing, benchmarking,
documentation, error messages etc., all work very nicely.

Overall, it lacks the instant gratification of a really good scripting
language. But I keep finding myself back in Emacs, writing more Rust code for
the fun of it. And I really enjoy the combination of low-level code, memory
safety, and a useful selection of functional programming features. I'm glad to
see a new language in this niche.

~~~
kibwen
This is great feedback, thanks. And if there's anything that you _don 't_ like
about Rust, please let us know now while we still have a chance to possibly
fix it! Only a few short months left until all of our mistakes are forever
entombed in Rust 1.0. :)

~~~
MichaelGG
Hi! I use F# for most tasks (from websites/JS generation, to packet capture
and indexing, call routing and billing processing), and some C where required.
Rust looks fantastic, and would give me the memory control I need when I need
extra performance. A LOT of it comes down to simply being able to stack-
allocate things; in F# I'm essentially forced to use the GC heap for even the
most trivial things.

Rust looks fantastic, and I'm very excited about using it. When I found out
about it and started reading how it worked, it was almost exactly what I had
been wanting, on almost every count. I really wish it had existed a few years
ago.

My comments are from someone that's just been playing around with the getting
started guide of Rust.

\-- Lack of custom operators limits expressiveness. For instance, look at
Parsec or FParsec. Why shouldn't they be allowed to exist in Rust? But if
custom operators _are_ totally out of the question, then what about user-
defined infix functions? (And then, why not functions with nearly arbitrary
codepoints as identifiers?)

\-- It seems that currying, partial application, and function composition are
sorta cumbersome in Rust. Is this a conscious decision, that idiomatic Rust
shouldn't be doing such things? Like " add >> inc >> print " being equivalent
to "|a,b| -> print(inc(add(a,b)))" ? In F# I use this kind of stuff all the
time, especially when processing lists.

\-- It seems there's a difference between function types. Like if I do "fn
foo(a:int, f:proc(int)->int)", I can call it with foo(1i, inc) if inc is a fn.
But if I first do "let f = inc; foo(i1, f)", that's an error. Offhand, I'd
assume this is due to lifetime management, but it feels a bit strange. When
writing HoFs, do I need to implement a version for each kind of function? Or
am I totally misunderstanding things?

\-- Sorta related, does Rust allow something like:

    
    
      let inc =
        let x = ~0
        || { let res = *x; *x += 1; res }
    

The idea is to expose a function that contains some private state. I remember
hearing that Rust changed the ownership stuff around a few times, but the
basic idea is to create a globally-accessible closure. Is this impossible,
requiring us to use statics to store the global state?

\-- Why doesn't Rust warn when discarding the result of a function if not
unit? Is it idiomatic Rust to return values that are often ignored?

\-- Even without higher kinded types, monadic syntax is useful. Is Rust
planning any sort of syntax that'd let users implement Option or Async? How
does Rust avoid callback hell? Or is this quite possible today with macros and
syntax extensions?

\-- Has Rust considered Active Patterns (ala F#)? With that, I can define
arbitrary patterns and use them with matching syntax. E.g. define a Regex
pattern, then "match s { Regex("\d") => ... , Regex("\D") => ... , _ => ... }"

\-- Consider allowing trailing commas in declarations; why special-case the
last item?

\-- And last but not least: Please, please, _please_ , reconsider type
inference. It's baffling why "fn" requires type annotations, but a closure
does not. What's more, why is there even different function syntax in the
first place? I've heard the reason that "top level items should have types
documented", but that's a very personal decision to make. It certainly isn't
something the Rust compiler should force me to do in all my code. Why do ya
gotta limit _my_ expressiveness? (Same argument I'd use for custom operators.)
Statics/consts should also have type inference. And note that these items
aren't necessarily public or exposed - but a private fn on a module still
requires type annotations.

~~~
kibwen

      > Lack of custom operators limits expressiveness.
    

I understand that this is going to be hard for some to swallow, but it is
explicitly a non-goal of Rust to be maximally expressive. :) New features are
motivated almost solely by solutions to concrete pain points in Rust code
(especially Servo). This may sound particularly Blubby, but the devs are well-
versed in Haskell (and Lisp, and Scala, and ML, and...). With respect to
custom operators and infix operators, they're taking the cautious approach of
leaving the option open for future versions of Rust, since they can be added
completely backwards-compatibly if there's significant demand for them
post-1.0.

    
    
      > It seems that currying, partial application, and 
      > function composition are sorta cumbersome in Rust.
    

There are two different camps in competition here. One camp wants Rust to have
default function arguments as per C++. Another camp wants Rust to have
automatic currying. These camps are in opposition because they both want to
control what `foo(bar)` does for a function `foo` that takes more than one
argument. So far the devs have resisted entreaties from both camps. Experience
post-1.0 may change this.

    
    
      > It seems there's a difference between function 
      > types.
    

Closures are really terrible right now and are in the midst of getting a
complete overhaul to be more useful and less hacky. :) Procs won't even be a
thing afterward. Please excuse our mess!

    
    
      > Why doesn't Rust warn when discarding the result of 
      > a function if not unit?
    

It does warn, for any type that has the `#[must_use]` attribute. This includes
the stdlib's `Result` type, which is basically Haskell's `Either` except
explicitly intended to be used for error handling.

    
    
      > Is Rust planning any sort of syntax that'd let 
      > users implement Option or Async?
    

I'm not sure what this means, as users can already implement Option. It's not
special-cased by the language in any way.

(As for the lack of HKT, that's a hotly-desired feature for post-1.0. It's
still a bit pie-in-the-sky, but the devs have acknowledged that it would be
very useful to improve our error handling story.)

    
    
      > Please, please, please, reconsider type inference.
    

Not going to happen. :) Requiring type signatures on top-level functions is so
useful that even the languages that allow it to be inferred tend to enforce
their presence via social pressure. In addition to providing powerful self-
documentation, this vastly improves error messages. Finally, I suspect that
Rust's trailing-semicolon rule (especially combined with the willingness to
ignore the return value of most functions) would interact poorly with function
signature inference.

    
    
      > Statics/consts should also have type inference.
    

IIRC this isn't possible, but I've forgotten the reason for now. It certainly
isn't motivated by any sort of philosophy.

~~~
MichaelGG
While I strongly disagree with limiting expressiveness, operators, etc., and
the thing about top-level functions is misleading (because a nested, private,
module isn't really "top level), this is a fantastic response and helps me
understand Rust a lot better. Thank you very much.

I hope things will change (esp. type inference, which while playing around is
really annoying, even if I eventually end up wanting to annotate. A REPL could
fix a lot of the pain.). But there's nothing out there that competes with
Rust, and the C-friendliness means I can fairly easily interop with languages
with more expressiveness ;).

As far as async/option, I meant something like Haskell's do notation or F#'s
workflows. This allows implementation of async code without callback hell or
the huge limitations of promises or whatnot. (But without HKTs, you can't mix
multiple monad types within one block.)

~~~
kibwen
While this is far from a promise, any future implementation of HKT would
likely be accompanied by a do-style notation. The `do` keyword is unused yet
reserved for precisely this reason ([https://github.com/rust-
lang/rust/blob/master/src/libsyntax/...](https://github.com/rust-
lang/rust/blob/master/src/libsyntax/parse/token.rs#L519)).

------
kibwen
I adore that someone like Armin is so delighted to use Rust. From what I've
seen of Flask and his other Python libraries, the level of consideration that
he devotes to API design is absolutely inspiring.

At such an early stage in the language's history, I'm optimistic that his
thoughtfulness in API design will become the baseline for the entire Rust
ecosystem. In this vein, I'd also like to credit Chris Morgan's Teepee
([http://chrismorgan.info/blog/introducing-
teepee.html](http://chrismorgan.info/blog/introducing-teepee.html)) and Sven
Nilsen's Piston
([https://github.com/PistonDevelopers](https://github.com/PistonDevelopers))
for devoting a great deal of energy to figuring out how best to structure Rust
APIs that play to the strengths of the language. It's a process of discovery
for all of us!

~~~
dbaupp
Don't forget Aaron Turon (employed by Mozilla to work on the design of the std
library), who, among other things, wrote the "fluent" APIs for process[1] and
task[2] spawning, which possibly inspired the redis-rs API Armin describes in
this post.

[1]: [http://doc.rust-
lang.org/nightly/std/io/process/struct.Comma...](http://doc.rust-
lang.org/nightly/std/io/process/struct.Command.html)

[2]: [http://doc.rust-
lang.org/nightly/std/task/struct.TaskBuilder...](http://doc.rust-
lang.org/nightly/std/task/struct.TaskBuilder.html)

~~~
bjz_
I'm so glad that Aaron is on the core team, focusing _specifically_ on API
design and ergonomics, rather than just the language. He has definitely been
applying much needed polish that we need for a slick 1.0 release.

~~~
sanderjd
Just wanted to also add that in an area of design with lots of strongly held
subjective opinion and rampant bikeshedding, Aaron has shown himself to be
incredibly thoughtful, well-measured, and diplomatic. Really a great addition
to the team!

------
haberman
> The truth is that the borrow checker is not perfect. The borrow checker
> prevents you from doing dangerous things and it does that. However it often
> feels too restrictive. In my experience though the borrow checker actually
> is wrong much less often than you think it is and just requires you to think
> a bit differently.

I would love to see this explored in more detail. The borrow checker is, from
what I can tell, one of the most important and novel parts of Rust. I'd love
to see more detailed examples of where:

1\. it kept you from doing something idiomatic that you _knew_ was safe but
you just couldn't convince the borrow checker of it.

2\. it kept you from doing something that _seemed_ safe, but then you realized
that it was actually telling you something important.

Also:

> Even if it would turn out that the borrow checker is not sound

Wait, is this an actual risk? Is there some lingering doubt that the borrow
checker is actually sound?

~~~
kibwen

      > it kept you from doing something that seemed safe, but 
      > then you realized that it was actually telling you 
      > something important.
    

One of the reasons that I know Rust is on to something is how often I've seen
this scenario occur on IRC. It's great to watch someone come in with a
complaint about appeasing the borrow checker, only to later realize that what
they were attempting to do was actually subtly unsafe.

For the former point about things that the borrow checker doesn't have enough
information to allow, see
[http://www.reddit.com/r/rust/comments/279yw3/borrowing_from_...](http://www.reddit.com/r/rust/comments/279yw3/borrowing_from_an_array_need_help/)
for an example.

~~~
aidenn0
It's also really a pain now to get the borrow checker to be happy with boxed
structures now that box isn't implemented in the compiler. You need to first
borrow the whole structure, and then things within it.

------
cageface
_I have a huge hatred towards both the STL and boost and that has existed even
before I worked in the games industry._

I really don't understand why STL gets so little love. It's a little lean on
features maybe but in my experience it just works, and it's _fast_. Once you
get your head around the iterator concept it's pretty simple to use. And with
lambdas in C++ I can write code that's almost as concise as Ruby or Scala.

Any strongly-typed, flexible collection & algorithm library is going to be
complex and require a learning curve.

~~~
stormbrew
In my experience the people who have strongly negative opinions specifically
about the STL have it rooted in one of these two things:

\- They haven't used it much in a very long time and have very bad memories of
tracing through the completely opaque SGI STL implementation and its
derivatives.

\- They include std::string and/or std::iostreams as part of the STL, neither
of which are part of the original STL and have all sorts of weird warts and
poor interactions with the generic algorithm-focused core parts.

Not to say there aren't other reasons people dislike it, but these are big
ones.

~~~
cageface
Probably true. I wasn't much of a fan either when I first used it in 1996. It
was extremely verbose, slow to compile, and tended to generate compilation
error messages that filled the screen.

But the experience of using the STL today with the niceties of C++11 and a
good compiler like Clang is _vastly_ better. I can now write code almost as
concise as Ruby that runs 100x faster, without usually having to worry about
memory management. I avoid using the streams stuff though. That chunk of the
library could use a serious overhaul.

I'm rooting for Rust because it's designed to address the problem spaces I
care about most but C++ has improved by leaps and bounds in the last few
years.

~~~
bjz_
Yeah, Clang has really improved the ecosystem as a whole, as has this decade's
updates to the language and libraries. But unfortunately they are all band-
aids over some very deep foundational problems that were decided decades ago
(I don't blame Bjarne by the way - he didn't have the benefit of hindsight).

I am glad we have a new language that takes the best from C++ and sets in on
reasonably solid theoretical foundation inspired by languages like ML and
Haskell. It's not watertight yet (unlike the formally verified ML), but it is
damn better than the current status quo.

~~~
ranran876
Are you coding currently in C++11/14 ? It doesn't feel "bandaid-y" at all.

------
jonesetc
I rarely have to do anything as low-level as rust would demand. More often
than not I find myself using Python, but I had the same feelings when I
started looking into rust a few weeks ago. It was exciting seeing the full
pattern-matching, especially.

I have a desire to get some experience in the area, but the problem is what to
make. Does anyone have any ideas for some smallish libraries that would
benefit the community? I'm certainly not a networking or concurrency expert,
so it's difficult to come up with ideas.

~~~
bjz_
What kind of areas are you interested/experienced in? What would you like to
learn? I'm sure there are tons of gaps out there that you could help fill.
Maybe the folks on irc.mozilla.org #rust might be able to give you some ideas.

~~~
jonesetc
Thanks. I'll definitely try out irc for some ideas. My general projects are
small automation tasks for myself as well as small web-based apps for myself
and friends. That's part of why coming up with ideas for something like rust
are a little tricky.

The only promising thought I've had is maybe implementing some sort of
template preprocessor that I can find a way to work into an existing rust
framework.

------
wisienkas
Started using rust just this week.

Used more hours than ever expected on it. Simple put you'll fall in love with
the compiler, because it point out so well your mistakes.

Another thing to note is that it greatly encourage you to fix your warnings
too. which for me coming from java and php world isn't something you'd give
much thought.

~~~
kibwen
I agree about the warnings. Normal Rust code is already so strict that a lot
of the warnings that you'd get from other languages are already compiler
errors, which means that issues that are merely good style (e.g. declaring a
variable as mutable when you never actually mutate it) can spit out warnings
without overwhelming coders and causing them to lapse into "I've already got
200 pages of warnings so screw this" apathy. It's a fine line though, and
something we have to remain mindful of as we add more warnings by default.

------
InfiniteRand
Rust actually makes me think a lot about Ada, if you want to program, you need
to program correctly.

Probably the reason I will not use Rust is the same reason I only look at Ada
in a professional context, I usually start projects with something quick and
dirty, then gradually refactor it into something better, rather than piece by
piece. Being forced to do it right the first time would likely just push me
more into doing less programming.

------
nixpulvis
In addition to being a great lang, I love all the little things. Like he
mentions, the doc tools and compiler are very nice.

~~~
bjz_
> the [...] compiler [is] very nice.

No doubt clang has been a good influence in setting the standard for gorgeous,
readable error messages with nice colored squigglies and arrows. Borrow check
errors probably the hairiest you get, and you get less and less of those as
you internalise the rules.

------
ObviousScience
I've been very interested in Rust for a while, but put off by the early
development status and the fact that it's undergone a few major redesigns. I
don't hold them against the language team in any sense, and actually think
more of them for it, since redesigns early are good if you realize something
else might be better or one of your original ideas just didn't work out.

Rather, I'm just curious when I can expect Rust to settle down and not have
frequent breaking changes, major redesigns of language features, etc. I've
heard it's the aim of the 1.0 release to have this property (which is a
reasonable goal in my mind).

Does anyone have a timeline on when it would be reasonable to start eyeing
Rust if I want more stability (in terms of language features) than it's had
during its development phase?

~~~
steveklabnik
You want to wait for 1.0. The plan is a release candidate around the end of
the year.

------
bsaul
I found the python version of the code so much more readable... is putting
"unwrap" and "ignore" everywhere becoming idiomatic in Rust ?

~~~
yen223
Python made the choice to sacrifice performance for much better readability,
and it shows. You can see the difference between code elegance when working
with strings in either languages, for example. The downside is that Python's
benchmark numbers are poor. Rust can get to within 1x C's performance; Python
would be lucky to get within 100x.

But I do share your concern about `unwrap`. Is it idiomatic to do `unwrap`s,
or is it better to define functions to accept and return Option<xxx>?

~~~
the_mitsuhiko
Unwrap only appears in simplistic examples. The correct "unwrap" is the `try!`
macro.

~~~
FreeFull
Once you reach the main function, you have to deal with the errors, since you
can't propagate them any further.

~~~
the_mitsuhiko
Your main function is most likely pretty empty and that's the only place where
you need to deal with hard failure. And that's the same in _all_ languages. If
you write in Python you don't just not handle exceptions either. Somewhere you
catch them down and present them to the user in a good way.

------
adultSwim
This is a good write-up.

I still think some kind of vanilla ML would suit a lot of people very well.

~~~
bjz_
What do you mean by 'vanilla ML'? I wasn't sure there were any really
around... Ocaml has tons of stuff added, and SML also has lots of added
extensions.

~~~
adultSwim
OCaml would be fine. It's a good language with a very efficient run-time.

I'm arguing that you could throw out most of the advanced features and that
would be enough for most people. Its best features are the core ones. That's
why I don't really care which specific flavor of ML you pick. Any would be a
big win over many languages in wide use today.

------
reflexer
let the hype cycle begin

------
coolsunglasses
Annnd if you'd like to be able to write code as fast as Rust but get it done
faster than Python or Ruby, take a look at Haskell.

\- ex-Python and Clojure user, teach Haskell now.

[https://github.com/bitemyapp/learnhaskell](https://github.com/bitemyapp/learnhaskell)

~~~
CmonDev
Rust is meant to be practical, Haskell is more for academia (horrible ML
syntax etc.).

~~~
lucian1900
Arguably that is either wrong or depends on taste.

Haskell has very little syntax in comparison to something like C or Python and
what little is has is very obvious.

I'd much prefer ML/Haskell-ish syntax in Rust, but I know I'm in a minority.

~~~
Symmetry
I agree with you, but Rust is mostly targeted at C++ developers so it makes
sense that they'd use C++isms where they it wasn't crazy. Examples of crazy
being resource declaration mirroring use.

------
_pmf_
Easy cross-compilation, motherfucker! Do you have it?

~~~
kibwen
Yes, by passing a target to the compiler via the "\--target" flag.

------
pekk
Disappointing how this author's hyper-criticism of Python is not applied
equally to Rust, presumably because Rust is newer and this author has other
bones to pick with Python. If Rust has a problem, he will sell that it is
charming (e.g. "it makes you think", "you just need to think differently",
"needs more love"). The glass will be full any day now! But if any new effort
in Python is not absolutely perfect or just not to his personal taste, he will
sell that it's because Python is a horrible pile of shit because nobody
listens to him. The glass isn't only half empty, it is also too hard, too
brittle, too cold and actually also too warm and it turns out that not even
its transparency is a good feature.

After several years of this routine, it has become very old. For God's sake,
if your ex is so bad then just move out of her house already. Don't just keep
eating the dinners she prepares and complaining about them and saying you'll
move out. Actually move out and stop talking about her all the time. Yet
another article about how you can't stand how she clips her nails is not
helping anyone.

~~~
mercurial
The criticisms of Python covers about one sentence, and they're all to the
point. I don't see how you can turn a well-written post 99% about Rust into
"hyper-criticism of Python".

> he will sell that it's because Python is a horrible pile of shit because
> nobody listens to him

I'm not sure we're talking about the same Armin here...

