Live data from Hacker News

My thoughts on OCaml

osa1.net

21–30 of 230 posts

Re: My thoughts on OCaml

#21
post #3

Why would a company use ocaml? I’ve worked in software now for most of my life, from small to the biggest companies. I’ve watched teams with senior developers use non mainstream languages to build services and just about every time those devs get board again, leave the team, leaving them stuck with this system that’s hard to develop and different from the rest of the orgs, eventually resulting in a complete rewrite.…

A language like ocaml excels when the input and output are program-like, and the problem can't be number-crunched by hardware. The typical example would be a compiler. Other examples would be model checkers, code generators for number crunching libraries, proof assistants, and so on. Complex problems, where you need to explore different avenues of approach quickly, and where symbolic manipulation is at the heart of the problem.

Thus, ocaml is best used as a "kernel" or "module". The contextual part of your system uses the part written in ocaml as a service.

But ocaml doesn't excel at problems which are common to a typical company. The people who are in the intersection of wanting to solve those problems, and ocaml developers are few. The same intersection with a more mainstream language is far larger.

However, if you find yourself with a problem at which ocaml excels, chances are the mainstream languages ends up falling short very quickly, because they tend to lack the abstraction features necessary for correctly handling the complexity.

Re: My thoughts on OCaml

#22

> Another example is the sequencing syntax ; and productions with as the right-most symbol: let test1 b = if b then print_string "1" else print_string "2"; print_string "3" > Here print_string "3" is not a part of the if expression, so this function always prints “3”. Well, yeah. Here's the equivalent Java code: void test1(bool b) { if (b) print_string("1"); else print_string("2"); print_string("3"); } You've chosen…

It's a non-issue IMHO. Just use parenthesis if you're unsure, then auto-format. You'll catch any issue that wan't caught by the typechecker by reading the diff.

Re: My thoughts on OCaml

#23
post #8

[flagged]

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.

Re: My thoughts on OCaml

#24
post #8

[flagged]

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.

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.

Re: My thoughts on OCaml

#26
I don't the author really gave Ocaml a chance. He argues that every language needs to have interfaces. I agree somewhat with that statement, but I think the truer statement is to say that every language needs to have some way of defining composition at a structural level.

An interface allows you to pass different "structures" to the same function so long as they adhere to the same spec. In Ocaml this is accomplished through modules, functors, and module signatures. Ocaml's module signature can play the same exact role as interfaces in Haskell, Rust or F#.

The module system is arguably more expressive than what can be accomplished to interfaces. To give an example, Ocaml suffers from the same problem as rust does with having two standard implementations of a async runtime. Just like rusts: tokio and async-std, ocaml has Lwt, Async, (and newly added to the mix Eio).

Whereas in rust most libraries just implement one of these systems, and you'll have to use compiler directives to support both. Ocaml's module system means that you can describe the async runtime as a signature and make your entire library generic to the async runtime it runs on top of. Most of the well-used libraries do this, and so you don't have to worry too much about which runtime you decide to use.

Clearly, a language that can do that must have in some place a system that can replace interfaces.

Re: My thoughts on OCaml

#28
post #8

[flagged]

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.

Re: My thoughts on OCaml

#29
post #8

[flagged]

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.

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

Re: My thoughts on OCaml

#30
post #18

ReasonML and ReScript are a (more or less the same) new syntax on top of OCaml. ReScript only targets JS, while ReasonML targets both JS and the native archs OCaml supports. Facebook and Bloomberg are using ReScript internally, afaik. Messenger.com is written in it. Facebook also maintains React bindings to ReScript. https://rescript-lang.org/ https://reasonml.github.io/

Rescript is completely excellent imo. I have used ocaml for years and while I like it more than most languages it's also weird and frustrating sometimes. Rescript uses the best parts of ocaml (type system & exhaustive pattern match, first class modules) to patch over the worst parts of js. It's almost alarming how effective it is to combine these two gnarly hostile languages like this.

I also work in typescript a lot and it's the obvious comparison/competitor there. While it has objectively "won" it's so so much worse than rescript. Its type system is much more complex, untrustworthy inference, and ultimately is still unsound lol. Ocaml's type system is truly a wonder. Extremely practically helpful, complex enough to express anything without becoming a full blown language in its own right like eg typescript and haskell.

Rescript compiles to very reasonable js and writing bindings is not particularly exhausting once you get the hang of it. I've been using it for a number of projects including completely irresponsible cases like deno fresh and it's been wonderful. What typescript could and should have been.

Post reply on HN