
100 days with Rust: a series of brick walls - another
https://brandur.org/fragments/rust-brick-walls
======
seawlf
As someone who has been programming in Rust for nearly a year, even for
commercial purposes, this article is baffling to me. I've found the compiler
messages to be succinct and helpful. The package system is wonderful. It's
dead easy to get something off the ground quickly. All it took was learning
how and when to borrow.

~~~
majewsky
I can see where the author comes from. I've been working with ^W^W fighting
against Tokio this week, and the error messages are horrible. Representative
example:

    
    
      error[E0271]: type mismatch resolving `<futures::AndThen<futures::Select<futures::stream::ForEach<futures::stream::MapErr<std::boxed::Box<futures::Stream<Error=std::io::Error, Item=(tokio_uds::UnixStream, std::os::ext::net::SocketAddr)> + std::marker::Send>, [closure@src/server/mod.rs:59:18: 59:74]>, [closure@src/server/mod.rs:60:19: 69:10 next_connection_id:_], std::result::Result<(), ()>>, futures::MapErr<futures::Receiver<()>, [closure@src/server/mod.rs:74:18: 74:74]>>, std::result::Result<(), ((), futures::SelectNext<futures::stream::ForEach<futures::stream::MapErr<std::boxed::Box<futures::Stream<Error=std::io::Error, Item=(tokio_uds::UnixStream, std::os::ext::net::SocketAddr)> + std::marker::Send>, [closure@src/server/mod.rs:59:18: 59:74]>, [closure@src/server/mod.rs:60:19: 69:10 next_connection_id:_], std::result::Result<(), ()>>, futures::MapErr<futures::Receiver<()>, [closure@src/server/mod.rs:74:18: 74:74]>>)>, [closure@src/server/mod.rs:78:34: 83:6 cfg:_]> as futures::Future>::Error == ()`
        --> src/server/mod.rs:85:15
         |
      85 |     return Ok(Box::new(server));
         |               ^^^^^^^^^^^^^^^^ expected tuple, found ()
         |
         = note: expected type `((), futures::SelectNext<futures::stream::ForEach<futures::stream::MapErr<std::boxed::Box<futures::Stream<Error=std::io::Error, Item=(tokio_uds::UnixStream, std::os::ext::net::SocketAddr)> + std::marker::Send>, [closure@src/server/mod.rs:59:18: 59:74]>, [closure@src/server/mod.rs:60:19: 69:10 next_connection_id:_], std::result::Result<(), ()>>, futures::MapErr<futures::Receiver<()>, [closure@src/server/mod.rs:74:18: 74:74]>>)`
                    found type `()`
         = note: required for the cast to the object type `futures::Future<Item=(), Error=()>`
    

I have hope that things will improve on this front when `impl Trait` lands.

EDIT: After re-reading this, I want to add that I don't mean to hate on Tokio.
I like the basic design very much, and hope that they can work out the
ergonomics issues and stabilize the API soon.

~~~
gnode
The grievances you and the article's author mention seem less to do with Rust
itself, and more to do with this seemingly horrible futures library. As far as
I can tell, it's still in the rust-lang-nursery, which is an indication it's
not ready for prime time yet.

~~~
tveita
I hope async programming doesn't become the standard in Rust. So much work has
gone into allowing clean and safe threading, but people seem to be led towards
the async libraries, which IMO solves a scaling problem only 1% of users will
have. It's great that they exist, but if you're not expecting to have a c10k
class problem, you can use threads and you'll probably have a better time.

~~~
geofft
If you're a library, creating threads causes side effects for the host
program, and doing async when called doesn't. For instance, in a single-
threaded program, it's always safe to call malloc() after fork(). In a multi-
threaded program, another thread might have called malloc() and picked up a
global lock; since only the thread that called fork gets copied (since you
don't want to do the other threads' work twice!), there's now a copy of that
global lock being held by a thread that doesn't exist, so calling malloc()
will deadlock.

My personal interest in Rust is as a C replacement, including as a replacement
for existing libraries that are written in C. While I agree threads can be
very efficient (after all, the kernel implements threading by being async
itself, more or less), they're annoying for this use case.

------
justinpombrio
> universally terrible documentation

Wait, what? Rust has what I consider the best documentation I've seen of any
language. The docs explain things at a high-level, but concisely, and have
numerous examples. The formatting is good, the keyboard navigation support is
good, it's well-linked, and it has convenient features like links to the
source and the ability to collapse everything but method headers for easier
browsing. And it's extremely easy to add docs to your own project.

Maybe there are some dark corners filled with poorly documented unstable APIs
that I haven't seen?

~~~
brandur
(Author here.)

I wrote this piece hastily, and it really wasn't intended for this broad of an
audience — I won't redact the existing wording I still think it's roughly
right, but I do regret a lot of it.

Rust's docs are _amazing_ in certain contexts — the book is great, the built-
in support for documentation on types/functions/etc. is amazing, and compiling
code examples are a very laudable idea.

What I'm speaking to here is more once you get into the broader ecosystem and
start using a lot of non-core libraries. Oftentimes I found that the front
page docs explaining the basic premise were concise and well-written, but that
things got quite a bit harder when you started diving into individual classes
and functions (put another way, as you started deviating from the happy path).
This doesn't apply everywhere, but often the comments are very minimal and the
documentation relies heavily on "types as documentation" in that there's a big
list of all the traits and the functions on those traits that are implemented.
In many, many cases there's little in the way of detail or examples.

I've written quite a bit of Rust now and have used many of the headliner
projects. So far there have been very few crates where I didn't have to resort
to eventually checking out the source tree and figuring out how to do some
particular thing by examining its source code and test suite. I won't call out
any single project in particular, but I found this to be the case in every one
of `actix`, `clap`, `diesel`, `error-chain`, `horrorshow`, `hyper` and
`juniper`, just to pick a few from the top of my `Cargo.toml` (it also
happened with many other libraries). It's great that you can do this and open
source is awesome, but ideally I could get by on just documentation, which is
what you can do in many other languages.

Unfortunately, read with little context, it sounds like the tone of my piece
was intended to crucify, but it's not. It can be simultaneously true that
Rust's docs can still use lots of improvement _and_ that the Rust team is
doing an amazing job of improving them (there's just a lot of work and a long
way to go). Both these facts are true with Rust.

~~~
wokwokwok
I wonder idly if it would be useful to have 'cargo doc deps' that would
generate docs for all your dependencies (or top level dependencies) in a
project.

The rust docs are super useful, but not everyone bothers to publish them, and
people tend to forget to pit full working examples in them.

~~~
dbaupp
'cargo doc' generates documentation for dependencies (along with the main
crate) by default.

------
dmix
> The wall is impassable until a point that you make a key discovery which
> lets you make your through. Often that discovery is a eureka moment – it
> felt impossible only hours before.

These moments are my favourite, or at least most memorable, parts of learning.
Which is what attracts me to hard, important concepts because they tend to be
the most rewarding once you begin to grasp it.

I'll never forget when SICP's connection between programming and abstraction
started to really click, after much effort, and the way it blew my mind,
despite having programmed for a couple years. Really grasping the fundamental
concept took the whole experience of programming to the next level - and made
learning other things easier like a rolling snowball.

The fact the author's walls never got "smaller" is a real problem, that can be
disheartening.

That said, brick walls aren't always bad things. Although it's often hard to
tell whether it's a reflection of a poor design/structure of the thing you're
learning, or just the learning material, or the learner themselves. Then there
is the question of "necessary evils" of steep learning curves which, who
knows, might be required entry-fee for a truly great language or tool (see:
Emacs/Vim).

Haskell was much the same way for me. Each cliff I climbed had a new big cliff
waiting. It got me into learning not just pure FP but also lambda
calculus/set/category theory. It felt never ending. I ultimately never went
"all in" with Haskell (maybe because of this) but what I did learn has been
very useful in my non-Haskell programming elsewhere, so it's not all for
naught. But it was admittedly a hard and significant time investment which
isn't for everyone... nor necessary for being a productive programmer. But I
don't regret it.

------
SCdF
I am currently learning Rust and I feel this intensely[1].

I really want to like Rust, but I feel like the way they cope with no GC
(lifetimes, borrowing) fights me at every turn, and really simple situations
in other languages[2] become these intensely painful situations. Every time
you think you've worked out how to fix a problem you find while you've fixed
that one you've actually created 2 more.

Want to have a data structure of variable size (eg a struct with an Vector in
it)? You can't do that, structs have to be fixed size. OK so I'll make it a
reference to a Vector. That's great, but now you can't have a factory function
because the lifetime goes out of scope. OK so I'll wrap my reference in a Box.
OK that's great but now your OTHER reference: a trait (because traits are also
of unknown size) is complaining. OK I'll wrap that in a Box as well. Sorry,
you can't wrap this trait in a box because before your trait requires
implementors to implement copy because at one point you have to use the trait
in more than one place and references break the lifetimes and--- __THROWS
LAPTOP OUT WINDOW __

I 'm going to keep chipping away at it for a bit longer, but I can feel my
interest waning.

[1] Except for the bad docs bit, I really like the docs, and the error
messages are definitely earnest in their attempts to help you.

[2] that I'm familiar with, which are no languages that don't auto-GC

\-- EDIT --

To everyone taking the first line of my intentional rant paragraph and
pointing out it works fine… you're correct, I am mistaken! Let me paste the
reply I made to the first person:

\---

You're absolutely right. What I really meant was that you can't have Vec<T>
where T is a trait without also wrapping that in a box, which for me in turn
doesn't work for a bunch of other reasons.

In any case, my point remains the same: it is very challenging-- at least for
someone used to just creating data structures and letting GC handle it-- to
build code that does what you want, and you spend large amounts of time
"fighting" the compiler. I am OK if people wish to peg that on me being stupid
or whatever, it doesn't change the core point: it's hard for new people to get
into, and if you're wanting there to be less Electron apps and more native
apps things like Rust being easy to use seems important for that.

~~~
tkzzbneig
It's important to note that in C++ you can easily run into problems with what
you're describing: structs (objects) with different sizes being put into a
vector. You may very well get the program to compile, but then run into odd
bugs which come about because your objects get clipped to the size of the
smallest possible (the base class). So any overridden methods which expect
extra data in a subclass will not behave as expected.

So what you usually do here is have a pointer and a VTable and all that jazz.
But there's been a resurgence in interest in putting data into contiguous
blocks of memory. Check up on data driven design.

I don't think it's fair to compare GC'd languages to Rust's complexity. At
least, compare C to Rust. But still, to be truly fair, weigh the usability
differences against the safety differences. There are a lot of trade-offs here
and perhaps this isn't the right way for you to go forward, but keep a broad
view of the other aspects at play.

~~~
geezerjay
> It's important to note that in C++ you can easily run into problems with
> what you're describing: structs (objects) with different sizes being put
> into a vector.

This is simply wrong.

> You may very well get the program to compile, but then run into odd bugs
> which come about because your objects get clipped to the size of the
> smallest possible (the base class).

That has nothing to do with object sizes. You're describing the object slicing
problem

[https://en.wikipedia.org/wiki/Object_slicing](https://en.wikipedia.org/wiki/Object_slicing)

The cause of this problem is ignorance and incompetence regarding fundamental
aspects of the language.

~~~
pcwalton
> The cause of this problem is ignorance and incompetence regarding
> fundamental aspects of the language.

No! You can rationalize _any_ language problem away with this argument. That's
why it's a fallacy with a name: "no true Scotsman" (as in: "no true C++
programmer would let object slicing introduce a bug").

Object slicing is a problem with C++, period.

~~~
geezerjay
> No! You can rationalize any language problem away with this argument.

Sorry, the sole problem is incompetence. Coupling incompetencr with the
inability to learn is a problem that no programming language solves. If you
insist in shooting yourself in the foot, it makes absolutely no sense to
complain that the gun is broken because it doesn't guide bullets away from
your foot when you intentionally aim at it.

The object slicing problem is C++ 101. It isn't the language's fault that
people who don't know the very basics end up doing mistakes.

~~~
pcwalton
"Don't use heap memory after it's been freed" is C++ (and C) 101 as well. Yet
if the bar for C++ competence is "never wrote a use-after-free", then your bar
for "competence" excludes essentially everyone in the industry.

Whether a theoretically "competent" C++ developer makes mistakes related to
object slicing is a completely uninteresting debate. Whether experienced C++
programmers make that mistake _in practice_ is the interesting question. And
they do.

~~~
geezerjay
> Yet if the bar for C++ competence is "never wrote a use-after-free"

The bar for C++ competence in that regard is RAII.

Furthermore, your strawman doesn't hold up. The object slicing problem is
actually like someone being foolish enough to cast a 64-bit int to a 32-bit
int and then complaining that the programming language is broken because the
32-bit variable doesn't hold 64 bits. Of course it doesn't. Why should it? And
why make excuses an play the pin-the-blame game when the problem is caused by
ignorance? Heck, you're assigning heterogenous objects of variable-length to a
data structure that by definition was designed to hold homogeneous sequences
of fixed-size objects, and even still you want to pin the blame on the
language? How, if you clearly don't know what you're doing?

~~~
hsivonen
> The bar for C++ competence in that regard is RAII.

If it was that simple we'd never need kungFuDeathGrip in Gecko. Yet, we need
it a lot: [https://searchfox.org/mozilla-
central/search?q=kungfu&path=](https://searchfox.org/mozilla-
central/search?q=kungfu&path=)

(KungFuDeathGrip is the pattern of introducing an extra RAII refcount
incrementer/decrementer on the stack to avoid subsequent method calls doing
something that would free an object from underneath the current stack frame.)

------
drbawb
>Even something as simple as abstracting a new helper function often turns
into a veritable odyssey because getting type annotations right can be so
difficult (especially where a third party library is involved).

This is a sentiment I can't say that I share or even understand. You have a
compiler doing inference, it will _tell you_ what the types are if you ask?

A lot of times when I find myself writing something where I'm unsure of the
concrete type -- I'll just stick a bogus type ascription in the expression
somewhere. Then I run `rustc` knowing full well that it will fail. Somewhere
in the error will be a message of the form "found <x> expected <y>" and now I
know what the inferred type is.

>The horribly anti-user futures system, compiler messages generated by a
misused macros that are second only to C++ template errors in how egregiously
difficult they are to parse, universally terrible documentation and lacking
examples, unstable APIs, type annotation hell, and so much more.

Given the author's dig at the `futures` crate though, I have a feeling a lot
of the verbosity in errors they are seeing is due to the extremely long chains
of combinators that the futures crate encourages. I haven't run into these
errors myself since I'm avoiding async IO in rust until an `await` style
abstraction becomes available. In my opinion: jumping into using an async
library/runtime that is undergoing heavy development is probably not the best
place to start when it comes to learning Rust.

I think this is one thing that Go definitely got right: having concurrency
baked into the language that encourages a "syncrhonous-style" of programming
is absolutely the way to go for approachability. I'm not sure that I'd go so
far as to call `futures` user-hostile, as the tokio devs are doing great work,
but it certainly isn't user-friendly yet.

~~~
majewsky
> A lot of times when I find myself writing something where I'm unsure of the
> concrete type -- I'll just stick a bogus type ascription in the expression
> somewhere. Then I run `rustc` knowing full well that it will fail. Somewhere
> in the error will be a message of the form "found <x> expected <y>" and now
> I know what the inferred type is.

I've found myself doing this a lot in order to find the type of an expression.
I stick it in a variable, add an `variable.asdf();` somewhere and look for the
error message "no method asdf() on type <x>".

------
vvanders
I was following along until this:

> universally terrible documentation and lacking examples, unstable APIs, type
> annotation hell, and so much more.

The docs in Rust are by far some of the best I've seen, without specifics it's
really hard to understand what issues he hit.

~~~
b0rsuk
They're completely different kind of docs that Python's. Python's are written
by hand, with many examples and tips how to use the various tools. Rust's
documentation very much feels generated, and the last time I checked methods
were not grouped. So vast portions of a page are consumed by variants of
methods (overloaded methods?) which work exactly the same except they take
different argument type. Python documentation is text with methods and code
samples inbetween. Rust's documentation is like someone iterated over
functions and types and printed a message for each. There's A LOT of
redundancy.

~~~
vvanders
You mean like how Vec has a ton of examples?

[https://doc.rust-lang.org/std/vec/struct.Vec.html](https://doc.rust-
lang.org/std/vec/struct.Vec.html)

FWIW I'm not a huge fan of Python's docs because I can't quickly scan them to
track down that one detail about a function I was using.

Rust's docs also let you collapse everything which makes browsing them much
faster.

~~~
andromeduck
The traits implementation section is god awful and in an utterly unusable
order because the ordering makes no sense.

I find myself always just looking at the source to make sense of things rather
than the docs which kind of defeats the point.

~~~
vvanders
That's because the trait section only shows what traits a type implements. If
you want to see how to use a trait just click that trait's name for the trait
specific documentation.

~~~
Paul-ish
Sometime I don't know what trait I need, but I do know what kind of operation
I want. In documentation such as Python's, I can "ctrl + F" for word similar
to what I want to do and I usually find what I need. In rust, that textual
description is usually hidden on the trait's page. This is probably more
frustrating to beginners who don't know what most of the basic traits are. In
general though, the standard library is better about this than other
libraries.

~~~
steveklabnik
The built-in Rustdoc search isn't perfect, but it _should_ search the textual
description for you. It might only search the first line? I should dig into
that code again...

------
Dowwie
I have been working with Rust, full time, for a little less than 100 days.
Like the author, I also came from Python (I authored Yosai).

Unlike the author, I haven't been hitting brick walls. I also have observed
all of the warning signs that the futures bridge on the tokio highway is
unfinished so I didn't cross the barrier and still try to use it anyway.

Instead, I have been working on myriad other synchronous parts with great
success. I've made substantial progress in this time largely due to the Rust
community and --- the Eco system! Sure, I've had to build custom parts but
there haven't been showstoppers.

~~~
pimeys
I'm from the Ruby community, did a year of Scala after leaving Ruby. I'm now
with rust and after the first struggle, I don't really have trouble with Rust
anymore. I know the design I need to do to get certain things done, I know
what is allowed now easily with purely concurrent Rust, and when do you need
to split things up into threads. Right now I can refactor a project from
threads to reactor in a couple of days and deploy to production with Rust. And
I know everything just works.

~~~
Dowwie
What type of projects?

~~~
pimeys
Async consumers that deal with events and trigger stuff on internal and
outside services. RabbitMQ in, http out, response back to RabbitMQ kind of
things.

------
pcwalton
I'm obviously about as far from the modal Rust user as one can get, but at
this point the language has completely melted away into the background. I'm
often tempted to write smallish scripts in dynamic languages, but even for
those I frequently choose Rust just for the Cargo ecosystem. In particular I
never see a reason to use C++ unless I'm contributing to a codebase that's
written in it.

It takes different programmers different amounts of time to get to this point,
and I certainly believe we can do better to make it easy to get up to speed,
especially when async I/O is involved. But it does come eventually.

~~~
danieldk
Same here. I used to use Python for small one-off scripts, but I now primarily
use Rust. I can write Rust nearly as fast as Python and Go now, plus there are
a lot of useful crates for the type of command-line utilities that I write.

For me the benefit is that a Rust utility usually works when it compiles, plus
I can easily deploy the binaries on other machines (without going through
another pyenv/pip dance).

To give an example: I work a lot with dependency treebanks on CoNLL-X format.
Over my past to years with Rust, I have accumulated a bunch of utilities for
doing things like paritioning data, merging treebanks, shuffling treebanks,
extracting forms/lemmas, checking for cycling graphs, etc. I use them nearly
daily:

[https://github.com/danieldk/conllx-
utils/tree/master/src/bin](https://github.com/danieldk/conllx-
utils/tree/master/src/bin)

------
steveklabnik
We've been putting a lot of work into making Rust easier to learn. A lot of
that stuff is just starting to land now. Some of it is inherent, but some of
it is also just rough edges. Including things that the author talks about
here.

So, my message is, we hear you! We're working on it. Might want to check back
in in a few months.

------
dman
Disclaimer: Am a C++ programmer

Watching from a distance I have to concede that from a safety, dynamism of the
community and package management using cargo Rust has improved upon C++ in
meaningful and measurable way.

However on the complexity of the language front, I wonder if Rust will also
join C++ in the realms of "too complex" 10 years from now. Would love to get
some Rust experts to weigh in here on their thoughts about managing complexity
of the language long term and whether being a simple systems programming
language is an end goal.

~~~
steveklabnik
Rust is certainly not the "end of history" for programming languages. But,
taking on that task is for future generations of language devs; it's an open
research question today. I can only hope so!

I wrote some thoughts about "complexity" and language design here:
[http://words.steveklabnik.com/the-language-strangeness-
budge...](http://words.steveklabnik.com/the-language-strangeness-budget)

I also think the difference between incidental and inherent complexity is
important...

~~~
dman
One question I had after reading your post is - We currently build languages
with purely additive models, ie features can be added to a language over time.
Overtime the interaction between features creates "incidental complexity". Was
wondering if you know of any languages that have been able to drop old
features / ideas in a controlled manner.

~~~
dottrap
Lua has been known to remove things. The language still remains small and
clean after over 20 years. The creator has given some talks about how breaking
compatibility (e.g removing features) requires its own thought process. There
are different types of changes. The easiest to change are the ones that can be
detected immediately in existing real world programs whereas the hard changes
are the kinds that could go silently undetected by users until it is too late.

------
Analemma_
I'm looking forward to the full article, because it's nice to know that I'm
not alone here. I too started learning Rust with great optimism, and had the
same experience: I expected that things would be difficult starting out, but
assumed it would get easier as I acquired more knowledge, and then it didn't.
Mostly this was for the same reasons as the author cites: Rust futures are
incomprehensible, and there is rarely documentation to answer simple questions
(one that I ran into the other day was "How do I parse a string into a
datetime in a particular timezone?", which took about an hour to answer,
compared to the 60 seconds it would take in something like C#)

I'm saying this as a lover, not a hater. I really believe in the mission of
Rust, and I really _want_ to like it, but I realized that even after a few
months of learning, it was still taking me orders of magnitude longer to
accomplish things in Rust than in C# (or even C++), and I wasn't finding the
tradeoff worth it.

~~~
hinkley
I’m observing some similar muttering in the JavaScript community with
Promises. Chain them incorrectly and you get an error with no actionable
context.

The most popular 3rd party promise framework in JavaScript collects extra
cause and effect data when you run the code in development mode. It helps but
it still isn’t always enough.

I fundamentally don’t understand how people still think writing tools and
libraries is the same process as writing production code. Which is to say: I
wrote it, I understand it, ship it!

It’s a profoundly different process. I don’t think we give enough kudos to the
people who can do it well.

I keep telling my ambitious jr devs the same two pieces of advice. The one
relevant here is: nobody is going to look at your code until something is
broken. Which means they are already having a bad day. Don’t make it worse.

~~~
vec
Don't leave us hanging. What's the other piece of advice?

~~~
hinkley
Oh. For a similar reason (nobody reads your code unless they're looking at a
problem): describe your piece of code in plain english. If you can make the
code work the way you just described it, the code will age better.

(It might not be the fastest, but everyone will know if it's correct. When
you're hunting for a bug it's important how quickly you can eliminate false
positives to get to the real culprit. And you can make good code fast but you
can't make fast code good.)

------
robotmay
I've been learning Rust for a little while, and while I agree that it can be
frustrating, it's nowhere near as bad as trying to learn Haskell. I regularly
get a friend of mine to explain things to me, because the documentation and
community for Haskell are 90% incomprehensible to anyone who doesn't have a
comp-sci degree or a higher education in mathematics. Example:
[https://wiki.haskell.org/Lifting](https://wiki.haskell.org/Lifting). It's not
that I don't get the concept (after being given a much better explanation),
it's just that the Haskell community in particular really seems to struggle
with communication. And I think that's where Rust is actually in a good place
for learning.

Rust has some confusing concepts, and it does feel like you're fighting the
compiler sometimes, but I can see what it's trying to achieve and it's
improving very rapidly. I find that I can more-or-less stumble my way through
it until I get where I want, as the documentation that is about is generally
well-written, even if it doesn't cover everything yet :)

And it's kinda fun!

~~~
weavie
> Lifting is a concept which allows you to transform a function into a
> corresponding function within another (usually more general) setting.

What's there not to understand? :)

~~~
robotmay
Yeah that bit was alright, it was everything after that I struggled with ;) As
an example; I don't know what a functor is. I've not come across that term in
anything I've done before, so I click on it to read up and get the definition:
"The Functor typeclass represents the mathematical functor: a mapping between
categories in the context of category theory. In practice a functor represents
a type that can be mapped over.", which uh, doesn't really help. I only did
mathematics to GCSE level here in the UK, during which I never came across
most of the terms used frequently in Haskell's documentation :D

There's a lack of examples of "real-world" usage in Haskell. e.g. here's how
you'd use lifting, in a practical example. e.g. why is lifting a thing and
what possible uses does it have when writing an application? Because to my
knowledge I've never done it before, so why is it good?

Thankfully my friend sent me this:
[http://adit.io/posts/2013-04-17-functors,_applicatives,_and_...](http://adit.io/posts/2013-04-17-functors,_applicatives,_and_monads_in_pictures.html),
which is a much better explanation. It's probably due to a difference in my
background (predominantly web, applications, self-taught etc) and the more
academic history of Haskell, but I find the vast majority of examples
irrelevant. Luckily there are a -few- books/tutorials around that explain the
language more clearly and why I might want to write software with it.

It's a shame because it looks like a really cool language, but it is seriously
hard to get into. Whereas with Rust, it just kinda makes sense to me.

~~~
weavie
I did mathematics to first year university level and didn't come across any of
the terms used in Haskells.

Our programmers group is currently working through category theory with -
[https://bartoszmilewski.com/2014/10/28/category-theory-
for-p...](https://bartoszmilewski.com/2014/10/28/category-theory-for-
programmers-the-preface/) \- and a lot of it is utterly bewildering, but at
least I am starting to understand some of what Haskell is going on about. As
for real world usage, however, I still have a long way to go...

------
dpc_pw
I think what happened here, is the author wanted to do something with futures
and the whole frustration is comming from not understanding that Rust Futures
are just not ready yet. The whole language and ecosystem has plenty of stuff
in the pipeline to make them better.

------
weregiraffe
This is a 100 sentences rant with 0 substances. Literally, there are no
examples at all of any "brick wall".

Why was this even posted here?

~~~
scrumper
? Plenty of examples.

 _The horribly anti-user futures system, compiler messages generated by a
misused macros that are second only to C++ template errors in how egregiously
difficult they are to parse, universally terrible documentation and lacking
examples, unstable APIs, type annotation hell, and so much more._

~~~
jorbrad
These are all very subjective. I personally love the error reporting; The
examples and docs are excellent; Many times I've needed unstable nightly api
features and have appreciated how easy it is to enable.

------
gnode
I feel like a lot of difficulties people run into with Rust are because
they're trying to do things the "right" way. You can often make your life
easier with liberal use of reference counted objects, instead of solving
difficult lifetime constraints, but it doesn't feel like the perfect way to do
it. Often people are pursuing zero-cost abstractions to their detriment. They
then compare the language unfavourably against languages where those zero-cost
abstractions weren't even an option.

~~~
sanjayts
I think this is an important point. When prototyping or developing one-off
utilities, I'm not looking to shave off CPU cycles or run everything under 6
MB. I wish someone would write a "Rust for <insert-gc-lang> Programmers". :)

------
szemet
_" getting type annotations right can be so difficult"_

I had the same experience. After getting lifetimes (more or less) this became
my largest headache... I wish for stronger type inference and features like
this:
[https://downloads.haskell.org/~ghc/7.10.1/docs/html/users_gu...](https://downloads.haskell.org/~ghc/7.10.1/docs/html/users_guide/partial-
type-signatures.html)

I feel my productivity (and code quality) would increase a lot. For example
right now I have to struggle so hard if I would like to write generic code,
while in haskell that's more or less the default thing (the compiler infers
it) if I just omit type annotations...

------
greydius
> I don’t like how little time I spend solving the problems that are
> interesting to me.

Welcome to systems programming.

------
roadbeats
PG had this comment about programming languages: The correct solution of a
problem is the most simple solution. Just like in math, you can solve one
problem in multiple ways, but the correct one is the shortest, beautiful
looking one.

When I look at Rust, it gives the feeling "could be simplified". Obviously
it's a new language and it comes with lots of cool stuff, but it looks ugly,
doesn't excite those who seek simplicity.

If I had the time to invest in learning Rust, I'd use that time for building
something new with any language that makes me productive.

~~~
steveklabnik
There are some ways in which Rust can be simpler; see my above comments about
learn ability. But a lot of the complexity is inherent in the choices we've
made for the constraints of the language. For example, including a GC would
make things much simpler in some ways! But it would also make it not
appropriate for many of the use cases that are crucial to Rust's existence.

~~~
zokier
The way I see it, Rust exposes more of the underlying complexity of things
which makes Rust itself appear more complex than its peers.

~~~
steveklabnik
Yes. The String stuff is the epotiome of this, IMO.

------
brabel
Exactly my feelings. Interesting how some people claim a rather different
experience. Rust was voted the most loved technology on StackOverflow, which
is unbelievable to me.

~~~
tzahola
It was probably done by the Rust Evangelism Strike Force.

~~~
weberc2
I don't think so. Rust is a brilliant language in theory, and for many high-
performance applications. There's a lot to love from afar. But it still hasn't
made good on its promises to be a great language for everyday application
development. That said, the goal is lofty and laudable and the community's
positive attitude and ability to take constructive criticism are world class.

------
jkarneges
As a long-time C guy, it's nice to see Rust as a modern replacement. But most
of the time, such low level programming is not needed.

The popularity of Rust and its friendly hand-holdy docs almost don't even make
sense for what it is, to me anyway. I suspect it will end up frustrating many
high-level developers.

------
zyxzevn
The problem with Rust is that it is very hard to program interconnected
graphs.

Basic Rust does not allow cyclic references, which means that almost every
graph needs to use special tricks to make it work. These tricks are variants
of reference counting. A trick that was copied directly from C++.

It feels like having to build a car with only a screwdriver and hammer. Each
section of your graph needs to be managed separately. With non-safe rust or
C++ you can put whole panels or sections on your car. And a garbage collector
works like a robot: usually effortless.

~~~
kam
The easiest way to build graphs in Rust is to store all your graph nodes in a
Vec, and use indices instead of references to refer to other nodes. Also a
cache locality win.

~~~
foldr
This is really the only practical way to do it, yes. But it's gross and means
that you have to write custom code to print the data structures. That might
sound trivial, but the ability to autoderive pretty printers is super useful
when debugging.

~~~
steveklabnik
Or just use petgraph, which does this for you.

~~~
foldr
That's fine if you're actually running a bunch of graph algorithms, but it's
not a good fit for, e.g., a parse tree where each node has a link to its
parent as well as links to its children. At least, I for one don't want to
have to pull in a relatively large library just to define such a simple data
structure.

------
valw
This sort of feedback would much more helpful and credible if you added what
sort of project you're using Rust on, your technical background, and concrete
facts (not just metaphorical opinions / complaints) about what goes wrong. As
it is, this article helps no one make informed technology decisions. See
[https://vimeo.com/9270320](https://vimeo.com/9270320).

------
AndyKelley
I have a similar story: [http://genesisdaw.org/post/progress-so-
far.html](http://genesisdaw.org/post/progress-so-far.html)

This is why one of the main features of zig listed on the home page is:

"Small, simple language. Focus on debugging your application rather than
debugging your knowledge of your programming language."

~~~
epage
Looks like your complaints were

> I fixed a lot of code after updating to the latest Rust compiler each day.

When referencing your experience, it might be good to point out that this is
before Rust hit 1.0 (commits mention Jan 2015 and 1.0 was released May 2015).
This problem goes away and a lot has improved about the language and ecosystem
since then.

> But nothing in life is free. GTK is sufficiently complicated that a Rust
> "safety wrapper" is in order. The one available was not complete.

I think GUIs might still be a weak point for Rust but it sounds like this has
gotten better. I hear a lot of positive reactions around relm

[http://relm.ml/relm-intro](http://relm.ml/relm-intro)

> And then I tried to abstract the font rendering code into a widget concept,
> and everything broke down. The Rust compiler has many false negatives -
> situations where it is a compile error due to safety, but actually it's
> pretty obvious that there are no safety problems.

Any examples of false negatives?

The main source of them is borrows that don't need to live to the end of the
scope ("non-lexical (borrow) lifetimes"). While in most cases this is easy to
work around (add a scope), things are progressing for the Rust compiler to
understand these.

------
encoderer
I consider myself a good enough engineer, and I've picked up a lot of
languages. Recently I built and launched a server agent for Cronitor. Going in
I knew it needed to be portable and compile to an executable. I considered Go,
Rust and C.

I decided to spend a day and build 3 versions of a basic Usage block to get a
feel for each. I'd never written Go or Rust, and only passable C.

I did C first and then tried Rust. I gave up. It was too much of a learning
curve for a ~3 mos project. I ended up using Go. I'll write up a blog post
soon, Go is not without challenges, but I'm comforted by blog posts like this
to see that I'm not the only mortal here still challenged by Rust.

~~~
sanxiyn
While people can learn Go in a day, it is basically impossible to learn Rust
in a day.

The only reason people can learn Go in a day is that Go is similar enough to a
language the person already knows. Rust is different enough to every other
language in existence (including C and C++) to make learning in a day
impossible.

I don't think "deciding to spend a day" is the right way to evaluate
programming languages. Unfortunately, it is the common way to evaluate
programming languages and Rust fares very badly in such evaluation, in my
opinion, much worse than its fair score.

------
brandur
Author here. I want to apologize a bit for the tone of this article — it was
written from a place of frustration, and this part of the site is very much
akin to a development journal — these are short articles without a lot of
concrete facts that are not really intended for broad or comprehensive
consumption. In no way is this meant to be an anywhere-near comprehensive
critique on Rust.

I'll quickly point out that Rust is my favorite programming language, even if
reading this piece in isolation would give you the opposite impression. There
are about a million things to like about it: The syntax, type safety, sober
choices around language design, built-in documentation facilities,
conventions, `rustfmt`, linting with `clippy`, toolchain management with
`rustup`, community (in the sense of project management and organization),
development momentum, ecosystem, and a whole host of other things are all
downright _incredible_. Some of the people working around the core are
undoubtedly some of the smartest throughout the entirety of professional
software.

That said, I wouldn't take back anything I wrote here because even when I read
it back today with a much more optimistic place (I bypassed many "brick walls"
that I alluded to since I wrote it), I still think it's true. Months later,
even after writing a lot of Rust, I often still don't feel productive.

No language is perfect, and it's probably healthy to have the occasional
counterpoint to its fairly consistent positive press. I've spoken to people
who don't know much about the language and refer despairingly to the "Rust
Evangelism Strikeforce", which I think is largely internalized rationalization
that what they've read is too good to be true, so there must some nefarious
element at work. Rust really _does_ deserve its good press, and hopefully the
occasional dissenting opinion and subsequent discussion will help convince
them of such.

IMO, Rust has a few existential threats — the one that I think most about is
that despite being well passed 1.0 at this point, there's a distinct lack of
pragmatism around getting core features like concurrency nailed down and
shipped. Futures and Tokio are widespread at this point, but the APIs are
still changing, and the error messages that they produce are still quite
awful. Even once they're fully feature-complete and stable, they're still not
going to be very pleasant to use — you have to think really hard about how
you're doing future composition. Contrast this to a concurrency system like
Go's, where you can more or less pretend that you're writing synchronous code,
and let the runtime take care of the heavy lifting. I love how much careful
thought and consideration is being put into the development of a cohesive
concurrency model, but unless it can get to the point where it's stable and
far more user-friendly, people (like me) who are trying to use the language to
build things are going to continue having a hard time.

In summary, Rust is awesome, the core team is awesome, and the development
community is awesome. I'm confident that the usability problems it has today
will be worked out.

~~~
steveklabnik
No worries <3

There's a lot of stuff coming down the pipeline that I think would help you a
lot.

> there's a distinct lack of pragmatism around getting core features like
> concurrency nailed down and shipped.

For one example; we're working _really hard_ right now on getting async/await
shipped, and dealing with ergonomics problems around it. The recent changes
are to make it simpler, not make it harder. For example, you should need to
think a lot less about future composition, since you'll be able to borrow
across futures, as just one example.

There might be a disconnect between what we're working on and what we're
perceived to be working on. Messaging is hard!

You're 100% right that criticism is the only way to evolve, and so I
appreciate calling out things that aren't great. Details help, but as you
said, this blog post wasn't intended for this audience, which is a problem I
feel quite deeply, personally. So I get it :)

~~~
brandur
Thanks for not taking it personally :) that's not always easy!

> _For one example; we 're working really hard right now on getting
> async/await shipped, and dealing with ergonomics problems around it. The
> recent changes are to make it simpler, not make it harder. For example, you
> should need to think a lot less about future composition, since you'll be
> able to borrow across futures, as just one example._ > > _There might be a
> disconnect between what we 're working on and what we're perceived to be
> working on. Messaging is hard!_

Sufficed to say that I can't wait to see these improvements come out. It may
end up being the case that I simply got started on this project a little too
early — six months from now many of my problems may have evaporated already.

------
isaachier
I'm not sure how easy Rust claims to be... The main idea here is " I love that
Haskell-esque feeling where a compiling program is usually a working program."
Rust will probably get easier, but it's main goal is safety.

The main problem I have with a pure safety focus is that the warnings often
feel like overkill for 99% of programs. For example, when gcc yells about
comparing signed and unsigned ints, I find that there rarely is a true safety
concern involved. I hope Rust is better than that.

~~~
grayrest
> For example, when gcc yells about comparing signed and unsigned ints, I find
> that there rarely is a true safety concern involved. I hope Rust is better
> than that.

In Rust these are treated as two completely different types so this is a
compiler error and not a warning. You need to explicitly cast one of them to
make the comparison and integer types are not automatically converted in any
way. You have to do the same for any other operation involving the two types
(e.g. addition).

You could certainly define the `ParitalOrd` trait for the two types to make
the comparison possible (I don't know the implications off the top of my
head). The language defaults to safe and explicit.

~~~
lomnakkus
> You could certainly define the `ParitalOrd` trait for the two types to make
> the comparison possible

I don't believe that's possible. Unless something changed relatively recently,
the trait implementation has to be either a) in the module where the trait
itself is defined (so the standard library in this case), or b) in the module
where the type you're implementing the trait for is defined (again, the
standard library). Since you can just modify the standard library,
implementing PartialOrd would not be possible for e.g. comparing u16/s16 (or
whatever).

------
weberc2
I've been dabbling in Rust on and off since 2014, and this has always been my
feeling. I thought my background in C++ would make things reasonably easy, and
while I have little fondness for C++, it's still easier to get things done
than with Rust, which is not at all what I expected given my 4 years with the
language.

There's a lot to like about Rust, but it falls far short of the "easy-as-Go"
promises made by many of its proponents.

~~~
Jweb_Guru
I've literally never heard anyone say Rust was as easy as Go.

~~~
weberc2
Really? I was hearing that 2 or 3 times a week before Tokio was popularized.
"Rust is as easy as Go for writing server apps!" "You don't need goroutines or
async for high performance servers; Linux threads work fine!". When people
started hearing about Tokio, many people seemed _sure_ it would be easier.
None of this is meant to bash these people; I think their goals and vision is
laudable and I hope they get there; I just think their optimism blinded them a
bit.

------
jokoon
The more I read about those new-wave languages, the more I end up thinking
that the simple languages like python and C are the clear winners.

I started to learn about rust, but honestly it feels like it has the same
design and features of ADA, in term of code correctness. It's a great thing,
but I still wonder if it's really useful for everyone. Usually ADA was used in
aerospace.

And I still believe C++ has a good future, of course as long as you keep using
the good parts.

~~~
pjmlp
If software companies got recalls and were sued for lack of quality like in
other industries, by now everyone would care about how their code gets
written.

~~~
jokoon
Sure, but that's a different debate.

If that would be the case, you would have much less competent programmers who
would be able to do their job properly.

I believe the software industry is still too young and immature.

~~~
pjmlp
On the contrary, only those able to meet the bar would be on the field, and we
wouldn't have self taughs calling themselves engineers.

~~~
jokoon
There is a big demand for programmers, so raising the bar doesn't make sense.

~~~
pjmlp
If companies payed programmers properly, gave training and benefits, there
wouldn't be lack of programmers.

Raising the bar makes sense in any engineering.

~~~
jokoon
It doesn't make sense if the country cannot afford to properly educate all
those programmers.

Don't shift the argumentation towards inequality.

------
rayascott
There are a few things in life you just should not do. One of them is jump
from your only language experience being Python into an advanced language like
Rust when you’re struggling to grok SQL.

~~~
actuallyalys
I don't care for this assumption that people who struggle with a programming
language are so inexperienced anything they struggle with is their fault. It
might be the case that Rust will always be an advanced language that beginners
should avoid until they've mastered something else, but feedback from
beginners could still make the experience easier for programmers who take the
ideal path and learn it as their second or later programming language.

The other reason I dislike this assumption is that it's frequently wrong.
Judging by the rest of his blog, the author _does_ grok SQL. I'm pretty sure
the Python to SQL example is either hypothetical or describes the author when
he first learned SQL well in the past.

I don't mean to pick on you. I just see this attitude repeatedly in software
development, and it leads to unnecessarily difficult software.

~~~
rayascott
“anything they struggle with is their fault.”? When did I say or even imply
that? I didn’t. Like the author, don’t make stuff up.

~~~
actuallyalys
Your comment stated that going from Python to Rust while struggling with SQL
is something "you just should not do". That implies that the struggles they
describe are the result of trying to learn Rust before they're ready—an
attitude I disagree with, even if it were true that the author was struggling
with SQL.

~~~
rayascott
Read what you wrote. You said that I implied that “ANYTHING they struggle with
is their fault.”

~~~
actuallyalys
I stand by "anything"—your post didn't make any exceptions. I should have been
clearer that I was referring to an attitude your comment implied rather than
an attitude you have, though, and for that I apologize.

------
EugeneOZ
I knew people are different. But if somebody can say that Rust compiler
generates complicated error messages, then I just can't imagine how different
people can be.

------
xliiv
Rust is not for you, and better stick to something which you are good at it.
Friendly advice :)

------
always_good
You can spend a month or two and get used to the bulk of Rust out of raw
exposure. After seeing the same compiler errors over and over, you start to
pattern match and learn how to jiggle the handle to get what you want.

For example, have you ever accidentally passed &Request across a thread
boundary? The compiler explodes with UnsafeCell errors deep within the inner
sanctums. It feels impenetrable for a while. You throw some clone() at it and
whatever your go-to guesswork is. Then 30 minutes pass and you realize you
just needed to pass Request instead of &Request. And at the end of i you
really haven't learned much beyond "I'll try that sooner next time."

I think that's the hardest part about Rust. It takes quite a bit of mastery to
actually understand and work around the more difficult compiler errors, like
one that seems to threaten the whole abstraction you were going for. But
adding a `+ Send + Sync` somewhere suddenly fixes it and it's not obvious why.
It can feel very precarious.

Anyways, I think most of Rust's issues are just tooling issues. For example,
imagine being able to hover identifiers to see their scope shaded in and where
they'll get dropped -- instead of just error-message ASCII art. Or being able
to hover something to see that it can do something because it implements this
certain trait.

