rwmj 11 hours ago

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.

  • simonask 9 hours ago

    > 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.

    • blarg1 3 hours ago

      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.

    • rwmj 5 hours ago

      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".

      • quamserena 5 hours ago

        I wish OCaml had more helpful error messages like these, right now it feels like I’m on my own solving some of the more inscrutable errors.

    • quamserena 5 hours ago

      I am surprised by this too. I wonder what OP is writing in Rust that requires monthly changes?

  • StopDisinfo910 9 hours ago

    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.

    • nesarkvechnep 8 hours ago

      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.

    • galangalalgol 8 hours ago

      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.

      • IsTom 6 hours ago

        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.

      • StopDisinfo910 6 hours ago

        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.

        • galangalalgol 5 hours ago

          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".

        • dlisboa 6 hours ago

          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.

          • StopDisinfo910 5 hours ago

            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.

    • quamserena 5 hours ago

      > 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

      • yawaramin 2 hours ago

        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!

ernst_klim 9 hours ago

> there is no equivalent to Java's toString or Rust's #[derive(Debug)]

There are devivers and a Format module for pretty printing.

https://github.com/ocaml-ppx/ppx_deriving

https://ocaml.org/manual/5.4/api/Format.html

  • quamserena 5 hours ago

    I am aware of this, but afaik it’s an external library? https://github.com/thierry-martinez/ppx_show

    • yawaramin 2 hours ago

      Re: the 'external lubrary' criticism. In Rust everybody says just use serde for serializing data and anyhow for error handling. But suddenly when we say use a ppx deriver in OCaml for effectively the same thing–serializing a type to a string–it's a huge problem. That's weird to me.

  • _flux 2 hours ago

    That's slightly disingenuous, as in the case of ppx_deriving you always need to state the type of the expression to call it, e.g.

        show_file
    
    or

        [%derive.show: (int * int) list]
    
    from the page. It's basically the same story for Format.

    What many other languages do that if you have an object, you can just transform that object into a string or output it with debug formatting, without any particular support from the object. It isn't much of a chore, but it is some; and polymorphic functions now need one extra argument for the formatter.

    I do recall there's a module for OCaml that can do "debug level" printing of objects by traversing their runtime structure, but that of course doesn't suite all objects.

    At least in Rust it's not automatic that you can print an object in the first place :).

adamchol 8 hours ago

I've been writing OCaml for quite some time now and I don't think any of those "pain points" are "pain" or really any problem with the language. I think they're more like a preference. The syntax or no forward references are just decisions that makes the language good in some ways and bad in others, and seems like you just really don't like the cons.

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.

_flux 10 hours ago

The article mentions that global type inference is painful, and Rust made the right call by requiring annotations, but actually I think the OCaml model is closer to the optimum: you can still annotate functions and perhaps you should (in fact the interface files are in my view great, but not everyone enjoys them), but the key benefit is that you can also use holes in such definitions, e.g.

    _ 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.
  • quamserena 5 hours ago

    I second the point that Rust types can get quite long. I usually use aliases where I can but that isn’t always possible. I think that sometimes people use boxing just to avoid these long types even if the code in theory doesn’t require an allocation

  • GCUMstlyHarmls 7 hours ago

    I imagine there's as sweet spot between type inference, an LSP "add type annotations" action and a "function missing annotations" warning option. Smooth out the exploratory stage, flip to "strict" with one button and a way to enforce "strict" mode.

    • quamserena 5 hours ago

      I actually find that annotated parameters and return types help me during the exploratory stage too otherwise I invariably end up making a typeerror somewhere and the errors aren’t helpful (the error shows up in the wrong spot, or the function mysteriously changes type)

myaccountonhn 7 hours ago

I employ some strategies when I work with OCaml to avoid some of these pain points: I avoid libraries with poor documentation, funky types, and preprocessors that don't throw proper error messages. So I skip ocamllex, Menhir and Reasonml because I've found like OP that the DX is too poor..

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.

  • Taikonerd 5 hours ago

    Is the DX of ReasonML poor? (I haven't used it.)

    If so, that would be unfortunate... because the whole raison d'etre of ReasonML is DX! Specifically, to provide a more familiar syntax for programmers coming from the curly-brace world.

    • myaccountonhn 3 hours ago

      When I evaluated it I just found the error messages not to correspond to the correct line, and/or be nondescript. Maybe that has improved.

  • quamserena 5 hours ago

    Maybe it’ll grow on me as I get used to it :) but e.g. I was really confused about a nonsense error in a match statement until I realized that it was because of a nested match statement.

    If you don’t use ocamllex/Menhir, what do you use for parsing & compiling?

user____name 10 hours ago

Reminded me of this comparison between Ocaml and Sml with regards to the purity vs practicality. [0]

The complaint about syntax is amusing, I get a bit annoyed when I see Rust syntax being inserted into Java/C-ish languages.

[0] http://adam.chlipala.net/mlcomp/

okhobb 8 hours ago

My favorite part about Ocaml is the type checker fwiw. Pretty much as soon as I appease it I'm guaranteed a 'working' program that usually does what I intended.

  • quamserena 5 hours ago

    My problem is that when you’re trying to appease it the errors it spits out can be confusing or in the wrong place

sshine 10 hours ago

Standard ML was my favorite language 2008-2012, and whenever people criticize the syntax, I shake my head. ML syntax is among the most beautiful, and most readable, to me. OCaml has a few features that bring the readability down a little, like the named fields prefix. The fact that it doesn't look like C or Ruby isn't bad. Erlang can be very readable, it just feels alien, which I presume is what people don't like.

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.

  • StopDisinfo910 9 hours ago

    > OCaml in particular could do well with terminators after e.g. match blocks to improve both ambiguity and error reporting

    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.

pjmlp 10 hours ago

Having learnt ML via Caml Light, back when OCaml was still going to be the next version, and known by its full name Objective Caml, I never considered any of that a pain point.

anthk 10 hours ago

On ML languages, you can try MLite first (it comes with a great manual and a paper too); and then you can jump into the biggies such as OCaML and maybe Haskell too:

https://t3x.org/mlite/index.html

phplovesong 7 hours ago

Im sorry but this reads like a noob trying out ocaml for the first time and beeing annoyed because it does not work like Java.

jpfromlondon 10 hours ago

Ocaml is one of the few languages I think you either really like or really don't.

  • lucas_membrane 9 hours ago

    Not for me. I spent a few weeks a few weeks ago trying to use it. Much I liked. Much I didn't.

    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.

shortrounddev2 6 hours ago

My main gripe with ML variants is the poor syntax around async (F#). For networked (web) applications, you begin to find that many or most of your functions are async, and wrapping them in computation blocks which come with their own internal syntax that eliminates a lot of the elegance of ML and makes your code look more imperative often feels like it defeats the purpose of the language.

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
Hendrikto 9 hours ago

> Usually partial function application is a bug

Dude, what?

  • dan-robertson 6 hours ago

    I think this is true. It can be easy to accidentally do partial application, especially with optional and labelled arguments, eg:

      let bar x y z = …
      let foo w x = bar x (f w x)
    
    The performance and evaluation order can be a bit surprising in this case, and the errors when updating bar can be hard to understand.
  • jlouis 7 hours ago

    It's my favorite line of the whole thing. There's so much which can be derived from that single statement.

  • quamserena 5 hours ago

    I would rather have partial function application be explicit rather than just omitting args because right now if you accidentally forget an argument (a bug) it isn’t an error there and instead becomes a type error somewhere else.

sanskarix 9 hours ago

what's always wild to me about these language debates is how much energy people spend defending syntax preferences instead of asking "does this help me ship?"

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.

  • hocuspocus 8 hours ago

    > 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.

    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.

    • lo_zamoyski 6 hours ago

      Indeed. The idea that increasing your hiring pool is good per se is like saying the best way to look for gold in California is to exhaustively sweep every inch of the state of California.

  • yodsanklai 9 hours ago

    > 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.

    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.

  • christophilus 8 hours ago

    Nah. You have to change how you hire. You can’t do the “45 years OCaml experience required” thing. But you absolutely can hire for obscure languages.

  • rixed 5 hours ago

    I wouldn't hire someone who can't learn such a small and simple language in a week.

    • cmrdporcupine 5 hours ago

      I mean, the issue is not learning the language. It's the best practices, the standard libraries, the language idioms, etc. A week is a tad unreasonable.

      A week to learn syntax? Sure. But to really be a fully operational battle-station engineer in a new language stack is probably 6 months to a year.

      I would however expect people to be able to submit code reviews for e.g. bug fixes and small features after two to three weeks.

  • cmrdporcupine 7 hours ago

    It's almost certainly the opposite problem. You can't find a job in it.

    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.