Hacker Newsnew | past | comments | ask | show | jobs | submitlogin

[flagged]


Yeah, I'm not sure I understand the author's complaint. OCaml has modules, associated types, anonymous modules, GADTs, polymorphic variants, and row polymorphism. All of which are kind of like interfaces.

As far as I can tell, the complaint is maybe that ocaml doesn't have something exactly like C#/Java interfaces (which I think is a fair assessment). So maybe the author is lamenting that they can't just rewrite their java code in every language?

Although, they also mention rust traits. Which at first blush look very similar to c#/java interfaces (at least closer than anything ocaml has). However, at least in my experience, rust traits don't quite fulfill the same niche as c#/java interfaces because rust cares a lot about when you can figure out the size of your objects. So every time I tried to use them like I would a C# interface, I wound up regretting the decision.

Ultimately, this article feels like a superficial "I don't like ocaml" blurb. There is a lot to be warry of with respect to ocaml. Although, the fact that ocaml still exists as a niche language with a lot of very significant maintenance and active development (effects + multithread recently landed), shows that the author did not pay sufficient attention.


The author is plenty aware of them, I can assure you (I used to work with him on the Glasgow Haskell Compiler; most Haskell programmers are plenty familiar with the ML module system, it's a highly coveted feature by many.)

Anyway, what they're referring to has been rehashed a billion times already in the relevant communities. ML functors being good has little to do with it; even with functors and modules, you're required to actually pass them around and construct them explicitly and use it at call sites. If you want a Set for Strings, you make an instance of the Set functor with the proper implementation of the signature which specifies the Set ordering (or whatever, assuming that's the signature needed), but then you still have to use the functor explicitly and pass it around. You can have more than one, for good reason, so making this explicit usage implicit is tricky. In contrast, in Haskell, there is one ordering for each (nominal) type, so there is no need to refer to specific instance of `Set String` or whatever to define the ordering. `Set` uses `Ord`, which has an unambiguous implementation. It is resolved implicitly for you.

A lot of people just call this an "interface." Hell, even I do that. It's just a generalized term for "ad hoc polymorphism" where you don't need to guide instance resolution, I guess.

The author even quite literally (in like, the next sentence) says that modular implicits would help this issue -- it would allow many uses of an instantiated module to become more implicit (e.g. uses of something like "turn this thing into a string for debugging" without having a menagerie of individual string_to_ functions). But they are not yet upstream. Even then, implicits have their own tradeoffs, and the design spectrum here has no clear winner. Even Haskell has adopted Backpack, which takes a different spin on the whole thing using mixin-modules (no functors), but tries to keep the characteristic power of functors available in a languages where typeclasses reign.

Much of this is also relevant in the design of theorem proving communities, e.g. Lean4, which heavily relies on implicit instance resolution in a similar form to modular implicits; yet it doesn't have modules in the ML sense. They really want this approach though, because in math you really do have lots of instances you might refer to by name. But in programming it's not always the same; implicit resolution of ad hoc instances is often very useful.

It's not really a weird or unusual complaint, it's been rehashed to death, but maybe it could be less ambiguous.


When writing about a language which has a well-known feature called 'interfaces', it behooves the writer to not use 'interfaces' to mean 'ad-hoc polymorphism' to avoid confusion. Not doing so led to the predictable confusion.


Great comment. Thanks!


I can kind of understand the author's complaint. A problem with OCaml is there are several different ways to achieve the same thing, and they're not compatible.

For example, you can do OOP-like interfaces/abstract classes with `class virtual`, but classes and modules don't mix together nicely. Your virtual class cannot abstract over modules, nor do functors abstract over classes.

So you end up either using modules/functors pervasively, or using objects pervasively. It's like there's two separate languages competing for use.

Using modules seems to be more common, but it overshadows some features of OCaml's object system which are pretty unique to it and useful: row polymorphism and functional objects.

Obviously, functors have a clear performance advantage because they're expanded at compile time, and objects have the vtable overhead.

I think it would be interesting to see a variant of OCaml which goes all-in on the object side of things. Strip away the modules and functors and a provide standard library based around functional objects.


Someone mind explaining how these help? I'm unfamiliar with OCaml, but looking at the documentation of modules, I don't understand what they have to do with interfaces in the OOP sense(EDIT: or, rather, ad-hoc polymorphism), which I'm pretty sure is what the author meant.


The point as I understand is that interfaces in the OOP sense try to mimic what modules do. Therefore OCaml not having them is not a serious accusation since everything you try to accomplish with interfaces / design patters you can and should be able to do with modules. Here is the article explaining the concept: https://www.pathsensitive.com/2023/03/modules-matter-most-fo... but I have to note that I never worked in OCaml so this is just my theoretical understanding.


To be fair, ocaml doesn't have something exactly like c#/java interfaces. Given some problem that you might want to solve with a c#/java interface, you can also solve it with ocaml modules by flipping the coding structure on it's head. I'm not going to try to explain exactly what this looks like because I actually don't really like that structure of coding, so I don't feel like I'm going to do it justice.

BUT ocaml also has row polymorphism and polymorphic invariants, which you can use to get something much directly closer to c#/java interfaces. The major difference is that with ocaml it's structural typing and with c#/java it's nominal typing. However, at a high level you can write the code in a very similar structural pattern as with what you get in c#/java.


> I'm pretty sure is what the author meant.

Clearly not considering he mentions typeclass in the article.

Module signatures are similar to interface and parametrized modules allow you to do what you would do with abstract class: you define a signature and then write a module using these functions. Parametrized modules are more or less a generalization of functions which goes from module to module.


Sorry, I initially wrote 'interfaces as in OOP' to distinguish them from module interfaces, but had 'ad-hoc polymorphism' in mind. 'interfaces' is much too overloaded of a term.


Ocaml has no ad-hoc polymorphism but you can use parametrised modules to write generic code which you will have to specialise at some point. That brings you ninety percents of the way in term of what ad-hoc polymorphism is used for. It's more cumbersome but I prefer it to the complexity involved by what Scala does for exemple.


Would you not consider the object system to be ad-hoc polymorphism?


The OCaml object system is still parametric polymorphism (trying to pass itself as subtyping polymorphism through row variables) rather than ad-hoc polymorphism: there are still no functions that only work on a finite subset of types. In other words, a function may work on any objects that has a method `m`, but you cannot have the same method that has different implementation for `int` and `float`.


It uses structural typing not ad-hoc polymorphism. Plus it’s rarely used and it used to give hard to parse error messages when you made type mistakes. I don’t really see it as an adequate replacement for ad-hoc polymorphism.


The author brings up modules and functors. A more charitable interpretation is that they want ad hoc polymorphism but are handed parametric polymorphism instead.


Especially if modular implicits land, you get the best of both functions and typeclasses.

Pretty weird way to start the post.


That's a big "if". The author themselves mentions modular implicits and points out that they haven't been updated in something like five years. I don't think modular implicits are going to happen in Ocaml in our lifetimes.


Can you elaborate for us newer OCaml users? My first reaction to this critique/point is the author must want mli, right?




Consider applying for YC's Fall 2026 batch! Applications are open till July 27.

Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: