OCaml as my primary language

nukifw | 382 points

I saw a talk by someone from Google about their experiences using Rust in the Android team. Two points stuck out: they migrated many projects from Python, so performance can't have been that much of a concern, and in their surveys the features people liked most were basics like pattern matching and ADTs. My conclusion is that for a lot of tasks the benefit from Rust came from ML cicra 1990, not lifetimes etc. I feel if OCaml had got its act together around about 2010 with multicore and a few other annoyances[1] it could have been Rust. Unfortunately it fell into the gap between what academia could justify working on and what industry was willing to do.

[1]: Practically speaking, the 31-bit Ints are annoying if you're trying to do any bit bashing, but aesthetically the double semicolons are an abomination and irk me far more.

noelwelsh | 7 days ago

OCaml is probably my favourite language.

The most involved project I did with it was a CRUD app for organising Writer's Festivals.

The app was 100% OCaml (ReasonML so I could get JSX) + Dream + HTMX + DataTables. I used modules to get reusable front end templates. I loved being able to make a change to one of my data models and have the compiler tell me almost instantly where the change broke the front end. The main value of the app was getting data out of excel into a structured database, but I was also able to provide templated and branded itineraries in .odt format, create in memory zipped downloads so that I didn't need to touch the server disk. I was really impressed by how much I could achieve with the ecosystem.

But having to write all my database queries in strings and then marshal the data through types was tiring (and effectively not compile time type checked) and I had to roll my own auth. I often felt like I was having to work on things that were not core to the product I was trying to build.

I've spent a few years bouncing around different languages and I think my take away is that there is no perfect language. They all suck in their own special way.

Now I'm building an app just for me and I'm using Rails. Pretty much everything I've wanted to reach for has a good default answer. I really feel like I'm focused on what is relevant to the product I'm building and I'm thinking about things unrelated to language like design layout and actually shipping the thing.

birdfood | 6 days ago

I haven't worked in OCaml but I have worked a bit in F# and found it to be a pleasant experience.

One thing I am wondering about in the age of LLMs is if we should all take a harder look at functional languages again. My thought is that if FP languages like OCaml / Haskell / etc. let us compress a lot of information into a small amount of text, then that's better for the context window.

Possibly we might be able to put much denser programs into the model and one-shot larger changes than is achievable in languages like Java / C# / Ruby / etc?

_mu | 7 days ago

I tried to like OCaml for a few years. The things that hold me back the most are niggling things that are largely solved in more "modern" langs, the biggest being the inability to "print" arbitrary objects.

There are ppx things that can automatically derive "to string" functions, but it's a bit of effort to set up, it's not as nice to use as what's available in Rust, and it can't handle things like Set and Map types without extra work, e.g. [1] (from 2021 so situation may have changed).

Compare to golang, where you can just use "%v" and related format strings to print nearly anything with zero effort.

[1] https://discuss.ocaml.org/t/ppx-deriving-implementation-for-...

pmahoney | 6 days ago

DarkLang which was initially written in OCaml eventually switched to F#. From what I remember the main reasons were the library ecosystem and concurrency.

I'm know .NET in and out, so I might be biased. Most of the boring parts have multiple good solutions that I can pick from. I don't have to spend time on things that are not essential to the problem I actually want to solve.

I've used F# professionally for multiple years and maintain a quite popular UI library written in it. But even with .NET there still are gaps because of the smaller F# language ecosystem. Not everything "just works" between CLR languages - sometimes it's a bit more complicated.

The main point I'm trying to make is that going off the beaten path (C#) for example also comes with a cost. That cost might or might not be offset by the more expressive language. It's important to know this so you are not surprised by it.

With OCaml it's similar I'd say. You get a really powerful language, but you're off the beaten path. Sure, there are a few companies using it in production - but their use case might be different than yours. On Jane Streets Threads and Signals podcast they often talk about their really specific use cases.

1: https://blog.darklang.com/new-backend-fsharp/

JaggerJo | 6 days ago

What a brilliant article, it really puts to rest for me, the whole “why not use F#?” argument. In almost every OCaml thread, someone suggests F# as a way to sidestep OCaml’s tooling.

I’ve always been curious about OCaml, especially since some people call it “Go with types” and I’m not a fan of writing Rust. But I’m still not sold on OCaml as a whole, its evangelists just don’t win me over the way the Erlang, Ruby, Rust, or Zig folks do. I just cant see the vision

garbthetill | 7 days ago

I migrated from OCaml to Rust around 2020, haven't looked back. Although Rust is quite a lot less elegant and has some unpleasant deficiencies (lambdas, closures, currying)... and I end up having to close one one eye sometimes and clone some large data-structure to make my life easier... But regardless, its huge ecosystem and great tooling allows me to build things comparatively so easily, that OCaml has no chance. As a bonus, the end result is seriously faster - I know because I rewrote one of my projects and for some time I had feature parity between the OCaml and Rust versions.

Nevertheless, I have fond memories of OCaml and a great amount of respect for the language design. Haven't checked on it since, probably should. I hope part of the problems have been solved.

loxs | 7 days ago

OCaml is a great language without great tooling. Desperately needs a good LSP implementation to run breakpoints and other debugging tools on VSCode or other LSP-aware IDEs. I know there ARE tools available but there isn't great support for them and they don't work well

shortrounddev2 | 7 days ago

Question about terminology: Is it common to call higher-order function types "exponential types" as the article does? I know what higher-order functions are, but am having trouble grasping why the types would be called "exponential".

jasperry | 7 days ago

> Sum types: For example, Kotlin and Java (and de facto C#) use a construct associated with inheritance relations called sealing.

This has the benefit of giving you the ability to refer to a case as its own type.

> the expression of sums verbose and, in my view, harder to reason about.

You declare the sum type once, and use it many times. Slightly more verbose sum type declaration is worth it when it makes using the cases cleaner.

ackfoobar | 7 days ago

I wish somebody with this amount of experience would compare the benefits / shortcomings of using the ReasonML syntax. (The article mentions it once, in passing.)

nine_k | 7 days ago

I’d have liked to see the use of dependency injection via the effects system expanded upon. The idea that the example program could use pattern matching to bind to either test values or production ones is interesting, but I can’t conceptualize what that would look like with the verbal description alone.

Also, I had no idea that the module system had its own type system, that’s wild.

rybosome | 6 days ago

Some years ago I also wanted to make ocaml my primary language, but rapidly encountered problems: difficulty to install (on Linux due to the requirement of a very unusual tool which name and function I forgot), no response from community regarding how to solve that problem, no solid postgresql driver, ....

Wanting to use a functional language I pivoted to fsharp, which was not the expected choice for me as I use Linux exclusively. I have been happy with this choice, it has even become my preferred language. The biggest problem for me was the management of the fsharp community, the second class citizen position of fsharp in the DotNet ecosystem, and Microsoft's action screwing the goodwill of the dev community (eg hot reload episode). I feel this hampered the growth of the fsharp community.

I'm now starting to use rust, and the contrast on these points couldn't be bigger.

Edit: downvoters, caring to share why? I thought sharing my experience would have been appreciated. Would like to know why I was wrong.

raphinou | 7 days ago

The best bird's eye overview of OCaml I've seen yet. As a long-time OCaml user, I find it entirely fair.

tempodox | 6 days ago

As someone who uses OCaml for hobby projects, I appreciate how little the language gets in your way when you want to just “get shit done”, despite the language’s origins in academia and industrial uses.

The type system usually means that I might take longer to get my code to compile, but that I won’t spend much (if any) time debugging it once I’m done.

I’m in the middle of pulling together bits of a third party library and refactoring them over several days work, and I’m pretty confident that most of the issues I’ll face when done will be relatively obvious runtime ones.

chris_armstrong | 6 days ago

I'm sure there's merit to the language, but the syntax seems absolutely alien to me. Some attempt to look like verbose imperative code, a bunch of semicolons, and for some strange reason, hate of parenthesis.

Real life sample:

    let print_expr exp =
        (* Local function definitions *)
        let open_paren prec op_prec =
          if prec > op_prec then print_string "(" in
        let close_paren prec op_prec =
          if prec > op_prec then print_string ")" in
        let rec print prec exp =     (* prec is the current precedence *)
          match exp with
            Const c -> print_float c
          | Var v -> print_string v
          | Sum(f, g) ->
              open_paren prec 0;
              print 0 f; print_string " + "; print 0 g;
              close_paren prec 0
          | Diff(f, g) ->
              open_paren prec 0;
              print 0 f; print_string " - "; print 1 g;
              close_paren prec 0
          | Prod(f, g) ->
              open_paren prec 2;
              print 2 f; print_string " * "; print 2 g;
              close_paren prec 2
          | Quot(f, g) ->
              open_paren prec 2;
              print 2 f; print_string " / "; print 3 g;
              close_paren prec 2
        in print 0 exp;;
A function is defined as:

    let print_expr exp =
That seems pretty hard to read at a glance, and easy to mistype as a definition.

Also, you need to end the declaration with `in`?

Then, semicolons...

    open_paren prec 0;
    print 0 f; print_string " + "; print 0 g;
... and even double semicolons ...

    print 0 exp;;
That looks like a language you really want an IDE helping you with.
manoDev | 7 days ago

ocaml is one of my favourite languages too, but I've found myself being drawn towards rust for my latest project due to its major superpower - you can write a rust library that looks like a c library from the outside, and can be called from other languages via their existing c ffi mechanisms. I feel like by writing the library in ocaml I would have a better experience developing it, but be giving up on that free interop.

zem | 6 days ago
[deleted]
| 6 days ago

In F# comparison. Modules "my opinion, strongly justify preferring one over the other".

Strong stance on Modules. My ignorance, what do they do that provides that much benefit. ??

FrustratedMonky | 7 days ago

Is OCaml somewhat suitable for desktop GUI app programming?

I saw this in the OP:

>For example, creating a binding with the Tk library

and had also been thinking about this separately a few days ago, hence the question.

vram22 | 6 days ago

> At present, I don’t know anyone who has seriously used languages like OCaml or Haskell and was happy to return to languages with less sophisticated type systems (though an interesting project can sometimes justify such a technological regression).

Recovered typeaholic here. I still occasionally use OCaml and I primarily wrote F# and Haskell for years. I've been quite deep down the typing rabbit hole, and I used to scorn at dynamically typed languages.

Now I love dynamic typing - but not the Python kind - I prefer the Scheme kind - latent typing. More specifically, the Kernel[1] kind, which is incredibly powerful.

> I think the negative reputation of static type checking usually stems from a bad experience.

I think this goes two ways. Most people's experience with dynamic typing is the Python kind, and not the Kernel kind.

To be clear, I am not against static typing, and I love OCaml - but there are clear cases where static typing is the wrong tool - or rather, no static typing system is sufficient to express problems that are trivial to write correctly with the right dynamic types.

Moreover, some problems are inherently dynamic. Take for example object-capabilities (aka, security done right). Capabilities can be revoked at any time. It makes no sense to try and encode capabilities into a static type system - but I had such silly thoughts when I was a typeaholic, and I regularly see people making the same mistake. Wouldn't it be better to have a type system which can express things which are dynamic by nature?

And this is my issue with purely statically typed systems: They erase the types! I don't want to erase the types - I want the types to be available at runtime so that I can do things with them that I couldn't do at compile time - without me having to write a whole new interpreter.

My preference is for Gradual Typing[2], which lets us use both worlds. Gradual typing is static typing with a `dynamic` type in the type system, and sensible rules for converting between dynamic and static types - no transitivity in consistency.

People often mistake gradual typing with "optional typing" - the kind that Erlang, Python and Typescript have - but that's not correct. Those are dynamic first, with some static support. Gradual typing is static-first, with dynamic support.

Haskell could be seen as Gradual due to the presence of `Data.Dynamic`, but Haskell's type system, while a good static type system, doesn't make a very good dynamic type system.

Aside, my primary language now is C, which was the first language I learned ~25 years ago. I regressed! I came back to C because I was implementing a gradually typed language and F#/OCaml/Haskell were simply too slow to make it practical, C++/Rust were too opinionated and incompatible with what I want to achieve, and C (GNU dialect) let me have almost complete control over the CPU, which I need to make my own language good enough for practical use. After writing C for a while I learned to love it again. Manually micro-optimizing with inline assembly and SIMD and is fun!

[1]:https://web.cs.wpi.edu/~jshutt/kernel.html

[2]:https://jsiek.github.io/home/WhatIsGradualTyping.html

sparkie | 6 days ago

Do they have a decent GUI library / binding yet?

amelius | 6 days ago

[dead]

danluvscock | 6 days ago

Extremely dated. No HKTs, no typeclasses (modules are not a good substitute), no call-site expansion.

pshirshov | 6 days ago

If I wanted to program in OCaml, id program in F# instead

moi2388 | 7 days ago