Recently, osa1’s My Thoughts on OCaml generated quite a robust conversation on Hacker News. Overall I felt the blog post was a bit too critical about OCaml. However, everyone has a right to their opinions and I respect whatever has been written.
Except for a couple of points, that post didn’t resonate with me, so I thought I should pen down my good/bad experiences with OCaml and see if others have felt the same way as me.
I’ve written a longish blog post here as sort my reponse! Please check it out!
Your feedback and comments would be useful!
If people think this is a worthy blog post, I’d like to post my blog on Hacker news also :-). If anybody feels enthusiastic about this write up do feel free to put it up on Hackernews yourself too!
Nice! Potential nitpick: you write “ppxlib (for metaprogramming in OCaml) doesn’t work with objects/classes”. That’s somewhat unfair, since there’s class-based AST traversal (mapping and folding) supported. Or maybe it’s unclear what you mean.
My understanding is that ppxlib will allow you do meta programming on modules and module signatures but not on OCaml objects and classes. So you would not be able to attach
@@ anotations to OCaml object methods and so forth.
Am I wrong?
I am not sure how you arrived at the notion that ppx annotations did not cover classes?
A quick glance with
ocaml -dsource can disprove the notion:
class c = object method m = () [@@method_annotation] end;;
Sorry, I relied on something based on recall which was wrong. Happy to have been corrected! Thanks!
P.S. Also @octachron @lukstafi – any other feedback would also be greatly appreciated too. Other things wrong? General agreement/disagreement with blog?
You seem to conflate “ad hoc polymorphism”, which is missing from OCaml but might one day arrive as modular implicits, with nominal typing (as opposed to structural typing). While OCaml’s support for structural typing has no equal, OCaml also supports nominal typing in a few ways: plain records are nominal, abstract types are nominal… There’s no built-in subtyping for nominal types, but one can have injection functions.
I think a positive of OCaml is that it’s a big language feature-wise, and yet the features play well together and each is there for a good reason.
Really appreciate your write-up! Being a Haskell user myself for quite a while, it’s interesting to hear thoughts about the language and some valid and constructive criticism.
Some time ago, Don Syme wrote some criticism of typeclasses. I do love typeclasses in Haskell and traits in Rust, but that post resonated with me and made me appreciate the lack of typeclasses as well. Good for mental sanity while using languages that lack the features you love
He suggests OCaml has the dangling else problem? As I see it, you can only claim that if the parser does not address the issue…
He wrote “The only thing that makes OCaml more ‘functional’ than e.g. Dart, Java, or Rust is that it supports tail calls”… Do any of these languages have currying?
No mention of modules…
For someone that worked on GHC, one could hope for something better.
Overall, he has some grievances that seem legitimate to him (fair enough), but the analysis, the tone, and the attitude are not serious…
Some compact feedback on osa1’s post:
I agree that having “something like typeclasses” in OCaml would be nice, and that this is one the main pain points with OCaml these days.
I wasn’t so impressed with the criticism of the standard library. Most languages get weird issues with their standard library over time (for example people frequently complain about Haskell’s
head function being in the prelude and have arguably “fragmented the ecosystem” with many alternative prelude proposals), and having other libraries offer better designs or better feature coverage is fine with me. We get into composability trouble for problem domains that require a sort of central coordination, for example Lwt vs. Async vs. Eio, but mixing stdlib-using code with core/containers-using code has never been much of an issue in my experience.
I broadly agree with the criticism of OCaml’s syntax, which has various flaws. Most language have syntactic flaws. Indentation-sensitive language have much less lack-of-bracketing-related flaws of course, but this comes with its own cost. I think that occasionally complaining about the syntax is an acceptable trade-off of using OCaml. (In fact people tried hard to offer better syntaxes at the time of the Camlp4 revised syntax, and most people never bothered because the issues of the current syntax are not that bad in practice.) I do wish we had better syntax error messages, and there is slow-but-existing progress on that (lrgrep)
My thoughts on @sid’s post:
I think that comparing OCaml and Haskell is fine, but I think that people also have a point to compare to larger ecosystems with better tooling (in some respects), such as the JVM or the dotnet ecosystem.
I agree that OCaml is “practical” and I think that is one of its main strength among the nice functional programming langages out there, even including Rust. If you forget about the tooling for a minute and think just of the code, programming in OCaml is typically easier than programming in Haskell or Rust, with a lower learning curve.
In some ways, the OCaml runtime has arguably become more advanced than the Golang runtime (and maybe the Haskell runtime).
I don’t agree with this and I think that it is the one aspect of the post where our affective relation to programming languages are putting rosy glasses on our eyes. The Go and Haskell runtimes are really impressive pieces of engineering and I they have years of production experience for mode of usages that we are now just trying in the OCaml world. Both the OCaml 4 and OCaml 5 runtimes are fine pieces of software, but I don’t think one could objectively see them as “more advanced” than the Go or GHC runtimes. It’s great that we have some primitive support for effects, but Go has had flexible control primitives underlying goroutines for a while, and Haskell (besides an impressive and sophisticated concurrent runtime and IO system) has recently benefitted from lexi-lambda’s impressive delimited-control primops work that certainly opens the door for runtime-supported algebraic effects for Haskell.
Thanks for your detailed feedback!
Yes, I think I overstated the impact of having support for effects in the OCaml 5 runtime now. I’ll correct this claim in the article. The Golang/Haskell runtimes have been doing things for years for which OCaml 5 has just acquired capabilities.
I did mention this in my blog post . My impression is that while the primitives exist, the work to build Eio-like/higher level libraries that use these primitives is still in the preliminary phase. For instance I read somewhere that Haskell might be interested in using io_uring for a future IO manager down the line – this is so that file IO is truly async on Haskell in linux. It would be interesting to find out – will they use C to build this new IO manager or will they use the new primops? If they use C then we can argue that OCaml has adopted a more advanced approach because apart from the lower level bindings to io_uring, Eio is basically written in OCaml.
I said it more than once but I think this is a red herring. The pain point is a lack of upstream integrated and mandated runtime type representation.
Even without a built-in deriving mecanism that would improve the eco-system by orders of magnitude, allowing users to define a single value
M.repr for their
M.t types which can then be used generically by a diversity of libraries of typed indexed combinators (formatters, comparison, equality, ui editors, random value generators, codecs with your pet serialization format, etc.).
It would be great to have an agreed upon runtime type representation. Are there any negatives to having this?
P.S. I’m assuming what you mean is that we should have an OCaml mandated version of things like:
Is my understanding correct?
I don’t think there are negatives, the problem is rather to design a good and forward looking one.
Here are a few others ones than the one you mentioned [1812.11665v1] Generic Programming in OCaml, LexiFi’s runtime types, GitHub - pqwy/tpf: Trivial/Tagless Polytypic Functions.
IIRC the delimited continuation primops in GHC provide multishot continuations by default with no option for linear or affine continuations. This wouldn’t make a useful substrate for implementing user level concurrency.
I’ve posted this on Hacker News.
Another example of your idea: ZIO Schema for Scala.
Thanks very much for this very enlightening blog post, @sid.
I’ve seen recent mentions of a couple instances of commercial use of the Erlang backend (PureScript in Industry - #5 by srstrong - Help - PureScript Language Forum), but I have no idea about how often this kind of thing happens.
(I’m not using Purescript. It’s just something I recently became curious about.)
Appreciate your comment !
So going from OCaml/Haskell to a niche backend of niche language seemed like a non-starter to me. Rather than caveat/qualify my language about Purescript in the blog post, I just assumed it was really small and ignored it for simplicity.