| I don't the author really gave Ocaml a chance. He argues that every language needs to have interfaces. I agree somewhat with that statement, but I think the truer statement is to say that every language needs to have some way of defining composition at a structural level. An interface allows you to pass different "structures" to the same function so long as they adhere to the same spec. In Ocaml this is accomplished through modules, functors, and module signatures. Ocaml's module signature can play the same exact role as interfaces in Haskell, Rust or F#. The module system is arguably more expressive than what can be accomplished to interfaces. To give an example, Ocaml suffers from the same problem as rust does with having two standard implementations of a async runtime. Just like rusts: tokio and async-std, ocaml has Lwt, Async, (and newly added to the mix Eio). Whereas in rust most libraries just implement one of these systems, and you'll have to use compiler directives to support both. Ocaml's module system means that you can describe the async runtime as a signature and make your entire library generic to the async runtime it runs on top of. Most of the well-used libraries do this, and so you don't have to worry too much about which runtime you decide to use. Clearly, a language that can do that must have in some place a system that can replace interfaces. |
And we're still talking about semantics here. How does it feel to use the language server? How does it feel to read the code? To build the language? Ultimately that's what users judge a language on. Yes, Rust in some ways has a worse form of abstraction. It is global, not fully generic and doesn't allow for overloading. But it creates a user experience that is nicer. It lets a user print something and compare two variables and do type conversions without having to scratch their head, read a forum post and import a library.