I don’t think this is that bad for rust though. For (a), it turns out that tail calls can make debugging harder, and they can be incompatible with certain type system changes you might want in an ML, and lots of OCaml (perhaps not a true ML?) in practice uses little explicit recursion and instead first-class functions with names like map and iter rather than recursion. So I don’t really think it’s very important. Rust also has these first-class iterator functions although a bit less of map for containers that can have many things (e.g. vectors). Rust iterations allow for writing code that is more functional when memory/performance are stronger constraints because the pipeline gets composed together instead of producing lots of intermediate objects. For (b) I guess the big difference is that the usual tool in functional programming for manipulating data is creating new copies of immutable data whereas in rust it is controlling ownership and then just updating it (a middle ground may be koka where you write code in the former style but the compiled code inspects recounts to potentially just mutate instead)
Why not? I’ve heard people say this about C too and I never understood it: LLVM and GCC both have optimization passes that perform tail-call elimination.
I think they also make debugging harder, aren’t used much in higher-level code, and aren’t necessary if you have good looping constructs.
I think the thing that tickles most people about Rust is the thoroughness of the type inference and type checking, which one generally gets from any ML.
If we have three stages: (1) system languages, (2) higher level languages like Dart, Java, C#, (3) very high level languages like Python and Ruby, then the those among the most popular languages in the ML family (OCaml and F#) comfortably occupy the same level as (2).
Maybe that's not what you're after. OCaml's more rare bytecode implementation (instead of native code) is about on par with Python and SML/NJ is pretty slow as well (although faster SML implementations like MLTon exist).
Rust's first mechanism for error propagation was the now-deprecated try!() macro, which did basically the same thing.
As a Haskell fanboy, this is how I feel about Ocaml and F#.
I guess I would even say it's like... most people just want the banana, but got a gorilla holding the banana and the rest of the jungle as well.
…and if you’re concerned about mutability you can use an immutable first language like Scala or F#.
This part specially about closures: https://blog.janestreet.com/oxidizing-ocaml-ownership/
https://blog.janestreet.com/oxidizing-ocaml-parallelism/ And yes, their changes introduce quite some additional syntax.