Rust's popularity despite the challenges of navigating the borrow checker has me rethinking what turns people away from Haskell. Specifically, the types are often blamed, but I don't think that's a major factor.
As somebody who likes Haskell but uses Rust mainly, I put backwards compatibility (of the language and base), the way library versioning is handled (multiple versions of a dependency don't break the build), as some big reasons I avoid using it.
You avoid Rust for how it handles library versioning? I'm maintaining a strict lack of opinion on that since Rust is so much newer that it hasn't yet encountered all the library versioning challenges older languages have.
Oh, I mean I use Rust because of its approach. I find it incredibly frustrating the way Cabal and OPAM require single versions of libraries in a build tree. Allowing duplicates does have issues, but I find those more tolerable. 😅
Like if I add library X to my Cabal file, and then later add library Y, there's always a chance that my library will fail to build with a confusing constraint error due to an incompatibility in some common ancestor dependency Z having an incompatible version.
All true, but I do think the Rust package ecosystem will hit its own strain points (e.g. tokio vs async-std today) as it grows and the pace of development gets less uniform. But we've been talking about external things almost exclusively here, and I agree, these are essential!
Really hoping that Multicore OCaml's effects and handlers will provide a nice example for future languages to follow - once it lands that is! Seems like a nice way of handling the problem of ecosystems fracturing along sync/async boundaries.
I'm not well in tune with the OCaml ecosystem, but my understanding is that competing stdlibs have already (unintentionally) caused some amount of fracturing.
Oh yeah, more talking about the yet-to-land Multicore OCaml project. Which will make it easy to make functions that are polymorphic over whether or not they can be run synchronously or asynchronously.
For example:
map : ('a ~> 'b) ->> list 'a ~> list 'b
which is sugar for:
map : ('a -[e]-> 'b) ->> list 'a -[e]-> list 'b
where `~>` is an effectful function, and `->>` is a pure function. This avoids stuff like Haskell's `mapM` and `mapA` etc.