> Environment capture. I often say (provocatively) that "I hate lambda", but lambda is actually (at least) two separate language features: one is a notation for anonymous function literals; another is equipping those anonymous function literals with environment capture. I don't really care either way about having such a literal syntax, but I really do dislike equipping it with environment capture and think it's a mistake, especially in a systems language with observable mutation. Early Rust had something called "bind expressions" which I copied from Sather and which I think are better (clunkier but better). Rust gained lambda-with-environment-capture in a single package which I didn't object to strongly enough, as part of trying to make interior iteration work on LLVM-with-no-coroutines, and this motivation was later removed when we moved to exterior iteration. But "if I were BDFL" I would probably roll back the environment capture part (it's easier to tolerate for non-escaping closures which many are, eg. in non-escaping coroutines / stack iterator bodies, but .. eh .. complex topic).

TFA loses me here. I rather like the Fn/FnMut/FnOnce business, though yeah, closures of dynamic extent are very limited unless you Box them to make them of indefinite extent... and so the whole language lacks that character that functional languages with GCs have, but it's still functional, just functional with a straight-jacket.

Earlier in TFA there's a mention of exterior iteration as in generators, and I want to point out that while generators are very nice, they are not a substitute for closures. Icon, for example, had iterators and first-class co-routines ("co-expressions"), but no closures, and so where one needed closures one had to use co-routines (costly!). It's true that with generators one needs closures less than without generators, but still, closures are very important.

> Traits. I generally don't like traits / typeclasses. To my eyes they're too type-directed, too global, too much like programming and debugging a distributed set of invisible inference rules, and produce too much coupling between libraries in terms of what is or isn't allowed to maintain coherence. I wanted (and got part way into building) a first class module system in the ML tradition. Many team members objected because these systems are more verbose, often painfully so, and I lost the argument. But I still don't like the result, and I would probably have backed the experiment out "if I'd been BDFL".

This loses me too.

It's great then that Rust didn't have a BDFL! :)

> Underpowered existentials. The dyn Trait mechanism in Rust allows runtime and heterogeneous polymorphism, a.k.a. Existentials. These types are useful for many reasons: both solving heterogeneous representation cases and also selectively backing-off from monomorphization or inlining (when you have those) in order to favour code size / compile time or allow dynamic linking or runtime extension. Early Rust tried to use these extensively (see also "first-class modules") and actually had an intermediate-rigidity type called an obj that was always a sort of Cecil-like runtime-extensible existential glued to a self-type record that allowed method-by-method overriding at runtime (almost like a prototype-OO system). Today's Rust strongly discourages the use of any such dynamic dispatch, a feedback loop arising from both technical limitations placed on them and a library ecosystem that's taken that as a sign never to use them.

This, on the other hand, is a brilliant observation and I agree with it as with much else in TFA.

> Tail calls. I actually wanted them! I think they're great. And I got argued into not having them because the project in general got argued into the position of "compete to win with C++ on performance" and so I wound up writing a sad post rejecting them which is one of the saddest things ever written on the subject. It remains true with Rust's priorities today, I doubt it'll ever be possible across crates (maybe maybe within), but as with stack iterators IMO they're a great primitive to have in a language, in this case for writing simple and composable state machines, and "if I were BDFL" I probably would have pointed the language in a direction that kept them. Early Rust had them, LLVM mostly made us drop them, and C++ performance obsession kept them consigned to WONTFIX bug status.

Oh dear. TCO is essential, IMO. I understand that it may not be possible in cross-crate cases, but still, TCO is very important.