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.
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.
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.
Thank you for your comment because I've been meaning to give OCaml a serious chance for a vary long time.
I like FP, so that was not a problem. But I found that lots of stuff was pretty hard for me as just an old guy trying to write some fancy little GUI apps to assist some of my other spare time activities. The project system, dune, was puzzling to me, and when I looked for clarification on-line it was pretty clear that I had lots of company. Not wanting to pass time writing code and seeing many potentialy useful packages available, I downloaded quite a few (actually, I downloaded not too many, but the dependencies required for those multiplied rapidly). Then I found myself managing multiple environments, because the different versions of this and that do not always work together so nice.
Some library code has to get imported some ways, some other ways. Etc, etc. Many tutorials teach the toplevel interpreter, but that's not recommended for projects of any size, and the other environments will choke on the code that works in the toplevel.
What I liked is that the OCaml ecosystem doen't look like it wants to control or ought to fear the next big thing. It's what you get when you have a lot of smart creative people who get inspired and do their best according to their own motivations and their own conception of quality. I admire that. I'm glad that I tried it.
    _ option list
is usually quite descriptive of what data you have, but still doesn't go into some detail you don't want to (sadly "int _ list" isn't supported by the type system). The types in Rust can sometimes get quite long, in particular if you want to avoid boxing and you're dealing with futures.The complaint about syntax is amusing, I get a bit annoyed when I see Rust syntax being inserted into Java/C-ish languages.
The big downside is the paradigm shift + inscrutable error messages.
It will make you feel dumb and/or unproductive for a very long time.
A lot of the type errors can be fixed by a compiler that cares more about error messages, and OCaml in particular could do well with terminators after e.g. match blocks to improve both ambiguity and error reporting. Some of the type errors can't easily be fixed; wrong function application by omitting some value somewhere has, so far, always led to misleading errors; are there any other examples than Elm that address these?
I also switched from ML to Haskell to Rust.
To me, the main downside of ML is the explicitly instantiated module systems not tied to the filesystem hierarchy.
Once you get used to traits and parameterised trait instances, bringing every module instantiation into scope after separately importing them is just slooow.
The standard library situation is also somewhat not great. Maybe I just never got used to it, but I sense that there are people think Jane Street Base is a must, and people who think it's completely overkill. OCaml programmers have a weird fetish with micro-optimization because the compiler lets you think about the asm output. It's a remarkable property of an otherwise high-level language that you can really care about the asm output.
You can use either begin/end or parentheses as terminators around any blocks of Ocaml for exactly that purpose.
> To me, the main downside of ML is the explicitly instantiated module systems not tied to the filesystem hierarchy.
That's one of the greatest strenght of ML actually and especially Ocaml where parametrised modules are everywhere and a required building block of generic code. A significant part of why the article complains about type for exemple is because the author doesn't know how to use the module system.
> Once you get used to traits and parameterised trait instances
I like modules a lot more. It makes the code a lot clearer than traits.
> The standard library situation is also somewhat not great. Maybe I just never got used to it, but I sense that there are people think Jane Street Base is a must
The standard library is a lot more complete nowadays that it was some years ago and Base is used by pretty much nobody outside of JaneStreet.
There are devivers and a Format module for pretty printing.
OCaml's real pain point isn't the syntax - it's that you can't hire for it. if you're building a startup and you pick OCaml, you've just cut your hiring pool by 95%. that's way more painful than learning a different way to write functions.
the whole "academic vs practical" thing is backwards. academic languages often have killer features that would save you real pain, but if your team can't debug it or you can't find Stack Overflow answers at 2am, none of that matters. language choice is a business decision, not a technical purity contest.
You can hire anyone who already understands pattern matching, closures, map/fold (these are more and more common constructs nowadays) and train them to learn OCaml. It's a simple language overall, especially if your codebase doesn't use any complicated features.
I hear this a lot about Scala and it's never been an issue in practice.
A smaller pool of candidates makes hiring easier, I'd much rather screen 20 résumés than 400. The typical candidate, whether experienced or willing to learn, is also better on average.
"We can't find qualified developers" usually tells more about the employer, in reality that means:
- We aren't willing to pay market rates.
- We don't invest in even the most basic on-the-job training.
- Seniority distribution is junior heavy; we expect one senior developer per team who can mentor all the other ones.
Or a combination of the above.
I know two relatively small companies that use OCaml, they don't pay anywhere near Jane Street salaries, but they're willing to hire people who show interest in the language and invest a little in their training. This works. On my end I've hired several people coming almost purely from Python, after a few weeks they contribute to fairly advanced Scala codebases.
There's a whole pool of people out there like myself who like to work in languages like this but don't because there's very few jobs in them.
When I heard people say they "can't hire for tech X" I usually find there's something else going on. I just left a job where they said they "couldn't hire" for Rust -- let me tell you... Finding Rust talent is not their problem. They have far more serious problems from which "retaining Rust talent" is a symptom.
The challenge with making good software is not language choice. It's communication and culture and making good foundational choices about software architecture that fit your problem domain. Writing code is the easy part, usually.
Dude, what?
Also, isn't freedom of annotating a function a good thing, instead of having a requirement on it? You can just explicitly annotate some stuff when you have a type error that doesn't feel right!
OCaml is way more simple from the type system perspective than Rust, I think it makes it great when you need a lot of iteration on you code.
One thing I do agree on are problems with the ecosystem. Maybe not quite in the specific area described here but man we got some problems in IO/concurrency/asynchrony space. Making a GOOD standard for it would just improve all our lives as OCaml developers.
But otherwise I don't particularly agree with OPs pain points. I personally find OCaml's syntax to be great. Very easy to write and read once you're used to it. And I previously thought that it's very important to annotate all types, as it would help with my thinking, but these days I find I'm more productive when I write out the code without types, maybe add a type here and there. I only annotate if OCaml's deduced type is too complex or generic.
In F#
    let Foo =
        async {
            let! data = getData() |> Async.AwaitTask
            return data.value
        }
Is this the best they can do? C# just has    async Task<Data> Foo() =>
        (await getData()).value;
Ive always wanted ML syntax like this:    let async Foo =
        let data = await getData
        data.value
I just dont write a ton of pure functions which have no I/O dependencies
StepBroBD•4h ago
[1] https://github.com/ocaml-ppx/ppx_deriving