Difficulty of monad types in Rust

You keep repeating this but you don't explain why you think they need to. It is an assertion without proof. Many languages did just fine with monadic construct without their own syntax in the past, and as I mentioned, so did Rust. Things change, but just the fact that some of them have special syntax now doesn't mean that this is a general necessity, or else implementing them without the syntax would have been impossible in the past.

Yes, I have heard that argument before. And those are largely stylistic issues. Both can be solved trivially by providing combinators that allow one to mirror loops and try and everything else. The standard Iterator trait with its combinators such as try_fold is the prime example that this is possible today.

I specifically wanted to avoid the dreaded "ergonomics" word, because nowadays that's being used as a trump card for shoving absolutely every last niche feature into the language without proper consideration. And the language team is sadly pushing this. I do care about ergonomics (that's why I switched from C++), but destroying core principles in the name of something that maybe 1% of the users need (I'm not only talking about async/await, but things like: one, two, three, four, five, six) is just generally misguided.

And you got it completely backwards with your last sentence. I've been using Rust for several years – I started using it because I loved they way it was. I have invested who knows how many hours in learning it, in writing opensource libraries in it, and even teaching it to friends that seemed interested. Why should I be forced to go away, hunting for another language and ecosystem, just because some newcomers are bending it in ways that completely hijack its original direction?

Furthermore, Rust is already pretty darn comfortable to use – it's one of the most "ergonomic" languages out there in fact. Not enough syntax isn't anywhere near its worst or most important problems. I'd rather have shorter compile times, or more precise rules around FFI / unsafe in general, or tier 1 AVR support, or variadic generics, or fully-fledged const evaluation. I'd take any of these over Yet Another Keyword To Learn™, and I'm still pretty comfortable without these features. They'd be nice, but not essential, and I can encapsulate my way out of the eventual and minor ugliness the lack thereof might eventually cause.

People complain about the borrow checker all the time: the proof is last week's 6 posts I linked to above, which all go something like "the borrow checker/the ownership model is hard and therefore we must change it". But once the authors of those posts make some effort understanding the underlying principles, and once they learn how to write idiomatic code, they almost invariably stop complaining because the issues simply go away if the code is structured properly.

Code using futures is not special: I have seen the exact same line of reasoning (or rather, set of complaints) in the context of async without a single concrete example as to what doesn't work and what people would like to work. At least I could then – as I often do with other kinds of non-idiomatic code – take a stab at rewriting it in a more structured, more principled manner so that the borrow checker can be happy.

2 Likes