As an engineer writing OCaml (and Rust too), I don't find any of this stuff to be a pain point. The syntax is fine once you get used to it. Anecdotally one of my colleagues who is learning OCaml and contributing to the code is using an AI to help get the syntax right and that works for him. Types in Rust are way more complicated and obscure than the ones in OCaml.
The ecosystem stays out of the way as much as possible - we are mainly interested in interfacing with C code directly, and OCaml (and Rust) make that pretty easy. I've been writing this project for over a decade and the language has been reasonably stable (OCaml 5 made some changes to the C interface, but we coped). Rust actually causes far more code churn - there's virtually a monthly cycle of some Rust compiler update requiring changes to existing code.
> Rust actually causes far more code churn - there's virtually a monthly cycle of some Rust compiler update requiring changes to existing code.
This is really surprising to me. Which changes have you had to deal with here? The only one I can think of is the major Edition 2024 upgrade, which changed the `#[no_mangle]` attribute to `#[unsafe(no_mangle)]`. But the old syntax still compiles just fine with the newest compiler using Edition 2021.
I guess it's because we use clippy to lint all the Rust code, combined with always pulling the latest Rust compiler (from Fedora Rawhide). But it's a real thing, there's a lot of churn.
The good thing is clippy / rustc has very good diagnostics and usually tells you "do X to fix this".
I think what clippy needs the most is a way to say, "make all clippy warnings as errors, but only for warnings up to Rust 1.80". And then devs can update that number whenever they want, as opposed to whenever new updates come in.
Or tie it to the current edition, or the current MSRV if defined.
A recent one I had was needing to include lifetimes to having to atleast specify the anon lifetime with the underscore. I forget what the actual circumstance was.
> Types in Rust are way more complicated and obscure than the ones in OCaml
For the most common cases, I agree. I always wondered why OCaml remained such a niche language, given that many of its nice features took decades to appear in more mainstream languages. I thought it was because the language was too complex and advanced for the mainstream audience. However, with the rise of Rust, I don't think so anymore. Rust is, in many ways, as complex as OCaml and, in certain cases, even more complicated. Yet, it's becoming very popular.
So my second theory about its lack of popularity must be correct: it has beginner-unfriendly documentation. In fact, I would even say it's unfriendly to engineers (as developers). The OCaml community prefers to see this language as an academic affair and doesn't see the need to attract the masses. Rust is an example of the opposite. It's a complex language, but it's pushing hard to become mainstream.
I stopped fighting this battle a long time ago. I think Ocaml just doesn't spoon feed people enough. They would have to actually read the documentation to understand and that's simply too hard nowadays so you end up which this kind of articles about "pain points" which are basically "I don't know what I'm doing and making a lot of mistakes, let me blame my tool".
Basically, when someone complaining starts by "I don't like the Algol-like syntax", obviously without saying it's Algol-like because that would require they actually know what Algol is, the rest is probably going to be extremely poor at best.
And here, it doesn't disappoint. Point 2, "I don't like type inference, it's too clever". Or you could just put type annotations at every declarations like every pieces of documentation ever produced on the language invite you to.
The type paragraph and the mentions of shadowing actually shows the author doesn't know how to use the Ocaml module system. For the neophytes here, it's the main standout feature of Ocaml. It's a bit like talking about C without knowing how to use pointers. I have seen people do that actually so I probably shouldn't be too surprised.
Menhir and ocamllex syntaxes are just slight twists on the actual syntaxes of yacc and lex. Nothing surprising for someone who knows both tools but I guess it's becoming a rarity nowadays. To be honest, the Ocaml compiler works exactly how you would expect a C compiler and linker to work. That makes it really simple and predictable for people who used to be C programmers but apparently completely inscrutable for young developers.
For printing, they quote "#[derive(Debug)]" in Rust but apparently they never reached ppx_deriving in Ocaml. It's a shame because it does exactly the same thing.
The whole conclusion with the weird segway about academics for a language which was purposefully designed to write provers and not as a research language doesn't even deserve to be commented upon.
Anyway, just go use Rust, bask in the hype, fight the borrow checker for things which don't require manual memory management, and leave us be. I think a significant part of why Ocaml is nice is that it is not appealing to many developers.
As soon as I saw the author uses OCaml for a class, I immediately knew the analysis will be somewhat superficial. No wonder, remembering my limited understanding when I was studying.
Thank you for your comment because I've been meaning to give OCaml a serious chance for a vary long time.
> They would have to actually read the documentation to understand and that's simply too hard nowadays so you end up which this kind of articles about "pain points" which are basically "I don't know what I'm doing and making a lot of mistakes, let me blame my tool".
Way to deflect any possible criticism x) I've used Ocaml for many years, and the syntax is undeniably a drag. There are inconsistencies, poor choices, none of which are a dealbreaker on their own but which together impose an ever-present friction. Death by a thousand cuts if you will. One of them explicitly mentioned in the article: the match statement.
> For printing, they quote "#[derive(Debug)]" in Rust but apparently they never reached ppx_deriving in Ocaml. It's a shame because it does exactly the same thing.
How do you print a list in OCaml? There's your answer as to why it's not the same thing.
There is no blame to defect. What’s supposed to be so weird about Ocaml syntax?
> How do you print a list in OCaml? There's your answer as to why it's not the same thing.
Don’t get your point.
You can ppx_derive on a list type. There is a feature specifically designed for this common use case. That gives you a pretty printer for a list. Alternatively you can tier the type pretty printer.
Is there supposed to be something special with lists?
What are the actual places you'd like to see improvement as an experienced user? A sibling post siggested concurrency, but from the outside those choices mostly seem to make sense. I've read complaints about opam/dune, but for simple stuff it seems to work fine.
The tooling remains so so. Opam is okay but it's not cargo. Dune is weird. Dune is actually very weird. I don't like Dune. It does work fine however.
Onboarding can be complicated. I'm complaining about new comers not reading the documentation before writting articles but objectively some concepts are so foreign, it's a bit difficult to see what you are missing. Module level programming for exemple is key to writing good Ocaml and it's quite a step if you are entirely new to functional programming. Effects are great but conceptually it's quite hard to get your head around them. Some fairly common libraries use Haskell influenced monadic interface. Yet another hurdle.
Traits have their flaws but I have to agree that having to be explicit all the time can be annoying. Modular implicit would be nice.
Concurrency is soon to be a lot better now that the effect system is mostly there and eio is landing.
The standard library is in the best shape it has ever been. I would still like more.
I do think maybe it should have stayed single threaded, or only allowed parallel iteration/loopsbfor fine grained parallelism. It was a completely safe language before 5 as long as you didn't pass -unsafe wasn't it?
It seems like you need to either be purely functional or have a borrowchecker if you want to have "fearless concurrency".
Is there a niche that OCaml fits really well with few packages needed? For example: Go has a great stdlib for networking (servers, etc); Rust is pretty good for CLI tools.
I've used OCaml for writing small compilers and it was really clean but that's a toy thing that will not see much real world usage.
Compilers, provers and static analysers. It's awesome for that. That's what the language was built for initialy: developing the Rocq prover.
It's surprisingly nice for web development also when you compile to JS. The ecosystem around Mirage and microkernel is quite impressive and if you want to build low level things and I for one like it significantly more than Rust for CLI tools.
It's a very versatile language honestly. It's opinionated enough that you have a clear idea of what would be the community choice but not so much that you can't just go to town with a different solution if it suits how you want to approach the problem more even it is an imperative implementation or even something object oriented.
I personally view Ocaml as basically a better Python with more features, better performance but without the huge success.
I don't particularly use OCaml anymore (though might in the future I guess), but one thing I remember is that sometimes when you had different parts of type system interact the compiler would just complain that you can't do that (mixing variants and GADTs was one such case I think?) without any real indication that this would be a problem before you try it. I get why this happens and I don't know how many people would run into it, but some kind visible notice or documentation for these cases would be nice.
> I stopped fighting this battle a long time ago. I think Ocaml just doesn't spoon feed people enough. They would have to actually read the documentation to understand and that's simply too hard nowadays so you end up which this kind of articles about "pain points" which are basically "I don't know what I'm doing and making a lot of mistakes, let me blame my tool".
The learning process for me has been as follows:
1. Make an error somewhere, maybe due to a misunderstanding
2. Error message makes no sense, or I don't know enough OCaml
3. Re-read the relevant portion of the documentation and examples
4. Hope that I can find the right way to do this somewhere
Compare this to Rust, which treats us quite nicely with descriptive errors that complement a vast and comprehensive reference manual. I do RTFM but a programming language is too big to learn all at once by reading a book before starting programming.
> Basically, when someone complaining starts by "I don't like the Algol-like syntax", obviously without saying it's Algol-like because that would require they actually know what Algol is, the rest is probably going to be extremely poor at best.
I am vaguely familiar with ALGOL but have never used it before. Do I need to put down OCaml and learn ALGOL first in order for my syntax complaints to be well-justified?
> And here, it doesn't disappoint. Point 2, "I don't like type inference, it's too clever". Or you could just put type annotations at every declarations like every pieces of documentation ever produced on the language invite you to.
I am doing this now, as I stated in the article. Compare against Rust's strictness, where bad ideas like not annotating function signatures are not allowed.
> The type paragraph and the mentions of shadowing actually shows the author doesn't know how to use the Ocaml module system. For the neophytes here, it's the main standout feature of Ocaml. It's a bit like talking about C without knowing how to use pointers. I have seen people do that actually so I probably shouldn't be too surprised.
I said in the article that:
> Enumerated types also dump all of their variants into the module scope
Is it wrong to say that they dump their types into the module scope? You have to put enum types in separate modules otherwise they will step on each other. (Is this understanding incorrect?) Maybe I will come to appreciate this as I learn more OCaml, but right now it seems like an unnecessary footgun.
> Menhir and ocamllex syntaxes are just slight twists on the actual syntaxes of yacc and lex. Nothing surprising for someone who knows both tools but I guess it's becoming a rarity nowadays.
Yes, I know this. The part that I don't understand is why OCaml wants to be like C with these tools in the first place. These tools exist in C because C doesn't have match statements, but OCaml does. What gives?
> For printing, they quote "#[derive(Debug)]" in Rust but apparently they never reached ppx_deriving in Ocaml. It's a shame because it does exactly the same thing.
ppx_show is an external library. Imagine having such a cucked stdlib that you have to call to an external library to print
> I think a significant part of why Ocaml is nice is that it is not appealing to many developers.
Clearly, that’s why people made a better syntax frontend for OCaml
You don't need an external library to print in OCaml. You just need it if you want to automate deriving a conversion function. OCaml erases types at compile time so the runtime doesn't know anything about types or how to print them. It's just how it works.
Re: better syntax frontend for OCaml. People really tried to, for many years. But it didn't work, there was never much adoption. And the funny thing was that as soon as people got comfortable with it they switched to the standard OCaml syntax because they understood it better and started preferring it. Ironic!
> I am vaguely familiar with ALGOL but have never used it before. Do I need to put down OCaml and learn ALGOL first in order for my syntax complaints to be well-justified?
Your syntax complaints will never be well-justified. It’s just a syntax family you are unfamiliar with, not an actual downside. You can either put up with it or change language. The syntax is however in no way inferior to C style syntax because that’s what you are used to.
> I am doing this now, as I stated in the article. Compare against Rust's strictness, where bad ideas like not annotating function signatures are not allowed.
There is no point in forcing you. The language doesn’t need to be strict. You can do whatever you want with your type annotation. It works just fine when you do annotate but no one is putting a gun to your head to do so if you just need a quick script. Best of both worlds.
> You have to put enum types in separate modules otherwise they will step on each other.
You do but it’s entirely normal and expected to define a new module inside your file in Ocaml and "let open" or assigning module is a common construct. It’s expected that you will not dump everything directly in scope.
> The part that I don't understand is why OCaml wants to be like C with these tools in the first place. These tools exist in C because C doesn't have match statements, but OCaml does. What gives?
They exist because generating parsers and lexers are nice and no one wants to learn a new language when they already know yacc and lex.
> ppx_show is an external library. Imagine having such a cucked stdlib that you have to call to an external library to print
No need to be vulgar. Ocaml has a lean standard library. That’s how the language is. You want macro and derivations you import them. They exist. Everybody uses them. The comment is a bit rich coming from someone who likes Rust.
> Your syntax complaints will never be well-justified. It’s just a syntax family you are unfamiliar with, not an actual downside. You can either put up with it or change language. The syntax is however in no way inferior to C style syntax because that’s what you are used to.
I think match statements should have an explicit `end` terminator or something so that you can nest them naturally. I think errors from accidental partial function application could be clearer. I think those two are pretty objective.
In terms of my subjective opinion the punctuation of C-style makes code hierarchy more clear, but at the cost of making it read less fluidly. I also think that `let...in` is weird and that Rust straddles a nice middle ground here by not having it but still having everything be an expression.
I like strict languages, and I like Rust for its strictness and robustness. I don’t like its standard library though, I wish it was more batteries included.
> I think match statements should have an explicit `end` terminator or something so that you can nest them naturally.
It’s unneeded.
You can explicitly delimit any expression in Ocaml by using begin … end or parentheses. It works for everything including match statements which are expressions. So you are already free to use an explicit end statement if you are so inclined.
The ecosystem stays out of the way as much as possible - we are mainly interested in interfacing with C code directly, and OCaml (and Rust) make that pretty easy. I've been writing this project for over a decade and the language has been reasonably stable (OCaml 5 made some changes to the C interface, but we coped). Rust actually causes far more code churn - there's virtually a monthly cycle of some Rust compiler update requiring changes to existing code.