I have used Jupyter notebooks with a Docker deployment in my prior courses for OCaml and Prolog, with support for auto grading (using nbgrader). Jupyter notebooks aren’t great for version control. Otherwise, it worked pretty well across multiple iterations of the course with new professors coming in and independently being able to use the infra.
Are these first-year undergrad courses? We can't assume students know anything about Docker or can even install packages on their systems. Some of them really have no idea at all, so pointing them to codeBoot saves a lot of time. Docker would definitely work for more experienced students though!
BTW, here's another quite nice feature of codeBoot: easy sharing! The following link will bring you to a suspended execution of 'print("hello, world!")' that you can then single-step.
I need a Linux VM to illustrate a couple of things in the last few lectures. Showing C undefined behaviour, memory safety issues and how that becomes security issues, compiling OCaml program to show test coverage, and being able to build unikernels. So can’t completely do away with Linux VMs.
For Unikernels, currently v86 is 32-bit only and OCaml 5 has dropped support for native 32-bit backends. In order to boot 64-bit unikernels, I’d need qemu. All of this could be done, but (a) this is likely to be quite slow (and the current emulation already is) and (b) the learning objectives are probably not improved a lot with the additional infrastructure. Hence, dropped it.
We don't even have the capability to build a _32-bit_ Unikernel now! That said, we _can_ boot 64-bit MirageOS unikernels on baremetal platforms. We use this capability in FIDES, which boots MirageOS unikernels on a bare-metal, security-enhanced, soft-core RISC-V processor: https://kcsrk.info/papers/fides_asiaccs_2026.pdf.
OCaml 4.x does support 32-bit native compilation, and I don't think it should be too hard to be able to boot them in the browser using v86.
What’s surprised me in the last few months is that agents are great at producing OCaml 5+ and OxCaml code, not much of which is out there in the training data. OxCaml’s strong types and modes seem to serve as great testable oracles to guide the agents.
I taught a course on concurrent programming based on OCaml 5 and OxCaml where almost all of the code in the teaching materials were vibe coded. I reviewed all of the code (because I was teaching it to a class of 50+ students) and frankly the agent writes better O(x)Caml (mostly) than me.
There's not that much downside since the annotations only change the performance characteristics of the program, and the static type system rejects inconsistent annotations.
There is some bizarre facility with hindley-milner based languages embedded in LLMs, they're basically automatically good at even very new ones like gleam and nanolang. I have a never-released-anywhere hobby ML that compiles to lua and coding models can write it fine. Better than it writes python or php for sure and those have huge corpuses in the training data.
I don't even have good conjecture about why this is the case but right now all my assisted coding is in MLs for this reason.
In OCaml 5, we’ve made it quite fast: https://kcsrk.info/papers/drafts/retro-concurrency.pdf. For us, the goal is to implement concurrent programming, for which a stack switching implementation works well. If you use OCaml effect handlers to implement state effect, it is going to be slower than using mutable state directly. And that’s fine. We’re not aiming to simulate all effects using effect handlers, only non-local control flow primitives like concurrency, generators, etc.
This talk is a _subjective_ take on how the OCaml programming language evolves, based on my observations over the last 10 years I've been involved with it. My aim/hope is to demystify the compiler development process and the tradeoffs involved and encourage more developers to take a shot at contributing to the OCaml compiler.
Happy to answer questions, but also, more importantly, hear your comments and criticisms around the compiler development process, ideas to make it more approachable, etc.
I'm at a conference at the moment so can't give a lengthy answer, but I'm the maintainer of virt-v2v, one large open source OCaml project (large if you include all the dependencies) which generates actual multi-millions in annual revenue, but is often overlooked in all this discussion of the OCaml ecosystem. Glad to talk by email some time.
[BTW we currently have open positions for two developers]
Thanks for sharing, I had no idea about this project.
Could you share some more details about where this project is used? Links to those open positions for OCaml developers would be interesting too, not for myself :-)
For converting VMs that run on VMware to run on KVM. After Broadcom purchased VMware a couple of years ago & raised prices (in some cases up to 10x), lots and lots of businesses are desperate to leave VMware. The open positions can be found on the Red Hat website if you search roles for "virt-v2v".
Right, we don't mention it in the advert because doing so draws in a certain type of academic person that we don't want to hire. Also because the majority of the code is actually in other programming languages, and we can easily train up (eg.) an ace C coder in OCaml if we need to.
This is not a direct comment on compiler development but on industrial projects in general: how do you begin contributing to something that is so large?
What should a beginner in compiler development, someone who has written a few compilers of their own, do to get involved in a project such as OCaml? I understand this issue is not specific to compilers, but is faced by any sufficiently large project. Still, I think it's an important issue. I believe there are many resources for people to get up and running in a field but not enough for them to make the next jump into industrial projects.
(I think this advice applies to most large open source projects)
Make sure you have installed and are using the software. Ideally you'd have an ongoing interest in it because it's something you use regularly (whether personally or for work).
Read first, especially the documentation, guidelines to contributing, mailing lists / Github issues / however else the upstream maintainers engage with each other.
Start small. Actually a great place is just to go and fix spelling mistakes and typos in documentation, code, comments, etc. Follow the guidelines for contributing to the letter, even if they appear over-complicated at first.
After you've engaged with small patches, build up. Look through their issues and (since you're using the software every day) find something that is an "itch" that you want to "scratch", and attempt to fix that.
I don't really need to go further because either at some point in this process you'll have become discouraged (for good or bad reasons), or you'll have found your community and will want to contribute more and more.
Also, of course, talk to people. Pitch your PR idea before writing it, so you can avoid hearing "oh, there's a much simpler way" or "we can never merge this approach because of X"
You are right that the dynamic arrays story does not read like a straightforward “how to inspire contributions.” But part of what I wanted to do in the talk was to show things as they actually unfolded. In OCaml compiler development, there is a very strong emphasis on correctness and long-term stability. That can make contributions, especially to core language features, feel harder than they might in faster-moving ecosystems.
The dynamic arrays case is a good illustration. What began as a small PR grew into years of design iterations, debates about representation, performance, and multicore safety, and eventually a couple of thousand lines of code and more than 500 comments before it landed. From one perspective, that looks discouraging. From another, it shows the weight we place on getting things right, because once a feature ships, it is very hard to undo.
That tension, between wanting to be open and encouraging contributions but also needing to protect stability, is something I think we should be talking about openly. My hope is that by making the process more visible we can demystify it and help contributors understand not just what happened, but why.
A point that I find missing in the timeline for dynamic array is that there have been implementation for dynamic arrays available in libraries for more than twenty years.
However, none of the authors of those libraries were really happy with their own implementation because those implementations had to choose between performance, API usability or thread safety.
When I closed the student pull request (which was a naive implementation with no unsafe features), it was with the idea that it was unfair to expect a beginner use to solve those issues.
The subsequent iterations explored different part of the design space before the final iteration which converged to safely using unsafe language features to reach a new local API optimum.
I think this is the tension in most software. If you want to have excellent and correct software it will take time.
And if you want more features with a "fix as you go approach" you will often have huge technical debt and get saddled with poor interfaces, often forever.
But, I think OCaml errs too much on the side of getting it right the first time. The result is that state of the art keeps moving far ahead. By the time OCaml "catches up" the field of programming languages has moved far ahead. So OCaml always remains the Jack of all trades and the master of none (IMHO).
I like the direction OxCaml is taking. But the problem is that no one has another 10 years to see its learnings get folded back into OCaml. There is a real chance that OxCaml may diverge so much that it becomes impractical to merge it into OCaml. Flambda2 is another great piece of software that may also take a long time to come into OCaml proper.
So I feel that things need to be "speeded up" if OCaml has to become a bigger ecosystem. You can see that some big projects are moving away from OCaml -- facebook for instance used to have their python typechecker in OCaml. Their new one, pyrefly is in Rust. This could be an isolated story, no doubt.
Now OCaml values adding features carefully to the language so that there is no future regret. But being slow and conservative has _not_ minimized regret. The "O" in OCaml i.e. Objects (and Classes) is almost ignored nowadays. Janestreet, a large industrial user seems to be actively against using the "O" part of OCaml.
So here we have gotten the worst of both worlds -- a language that is evolving slowly and a language that has large features that are almost soft discouraged. My primary language is Rust and not OCaml (mostly dabble in OCaml) so I may not fully know what I'm talking about when it comes to OCaml.
The distaste for the OCaml object system is mostly misplaced in the community. While first class modules can mostly replace them — sometimes you really need open recursion. Object types are also a very useful feature used by core libraries.
> and a language that has large features that are almost soft discouraged
It's literally just objects, one large (and early!) feature. Arguably too large compared to the rest of the language: first-class modules or polymorphic variants can handle most of their use cases while being much simpler, and faster than the existing class system. (Objects and object types without the actual classes are maybe ok.)
The only other controversial feature I can think of is Seq and that's just because it can be allocation-heavy. Then again ordinary OCaml lists are not much cheaper (thankfully immutable arrays are already in for 5.4).
Interesting. I'm still working my way through Correct+Efficient+Beautiful. My takeaway so far has been that Modules _are_ the "O" part of OCaml. I guess there's something more "traditionally" an object? Does that mean there were modules in Caml (or whatever the predecessor was) and it was decided classes might be a good feature to add?
Yes, the O in OCaml extends the type system with structurally typed objects and a classic OOP class system.
They're conceptually nice, specially the in-place object syntax, but the class syntax feels tacked on and the overall implementation is very naive compared to a proper OOP runtime like CLR/JVM/JS.
I suggest reaching for them only when first-class modules aren't enough (i.e. you need open recursion). Even then you could sometimes get away with polymorphic variant constraints, but that's admittedly harder to read and understand.
> By the time OCaml "catches up" the field of programming languages has moved far ahead.
Hard to reconcile with the fact that Ocaml had 90% of the features people like in Rust today twenty years ago, a module system which is still better than Haskell, and is currently implementing a full effect system.
It still pretty much ahead of every mainstream languages.
> a module system which is still better than Haskell
The module system though powerful is quite awkward and verbose. I personally prefer adhoc polymorphism (class/instance in Haskell, trait/implementation in Rust). That is really missed in OCaml and is likely to be missing for the next few years even though there have been (stalled) efforts like Modular implicits in the past.
Haskell and Scala seem to have many features lacking in OCaml. Some of those features are excessive I'll admit and OCaml can argue that it is more minimalistic (which is also useful).
Yes, effects are definitely a cutting edge feature in OCaml. But they are untyped which is a big limitation I would say.
TL;DR -- OCaml does many things well. It's a good language. My main point is that the language needs to speed up its pace of evolution. OCaml's lunch is being eaten up by lower level and performance oriented languages like Rust. At the higher level it is being squeezed by Lean, Haskell, Fstar etc.
> The module system though powerful is quite awkward and verbose.
Deeply disagree. It’s a lot easier to use and reason about that type classes. You can use Haskell if that’s what you want anyway. I’m glade Ocaml isn’t Haskell.
> Yes, effects are definitely a cutting edge feature in OCaml. But they are untyped which is a big limitation I would say.
APersonally I think it’s an insignificant limitation for a feature existing approximately nowhere else. Anyway I think we have safely killed your initial argument that Ocaml was somehow lagging behind.
I think it's just the nature of the beast, in this case. Serious "industrial" implementations of a programming language might stick around for a long time, and breaking things a lot can mar the appeal; getting it right the first time pays off in that case.
I think the acceptance threshold can be much lower in other kinds of tooling. "It is what it is", so to speak.
Add a sane deprecation process and this is much less of an issue -- see e.g. the Java language. Sure, it's not ideal to have multiple implementations of the 'same' data structure (if a better way is found, say)... but at least you aren't stalling everything and causing API interop issues for years and years.
It is often hard to see the shape of these things before a serious PR attempt is made. Each of the PRs reveals more of the shape of the problem being solved. Hard to skip them in practice, especially for new contributors.
Right. It is hard in general to compare performance or generated code across languages as they make different trade offs. Table 3 and 5 show compilation of our memory model to X86 and ARMv7. The compilation and the related work section discusses trade offs.
To summarise, atomic read and write in OCaml is more expensive than C++ since C++ SC atomics only establish total order between SC operations on not operations that are weaker but related to SC operations by happens before. We need stronger atomics for local data race freedom.
Our non atomic are also stronger than non atomics on C++ and Java. That said, The non atomic operations are free on X86 (compiled to plain loads and stores) and involve a lightweight fence before stores on weaker architectures such as ARM, Power and RISC-V. The performance results show that extra fences before stores have a barely noticeable impact on ARM and Power.
Still early days, but I had done some exploratory work in the past on Reagents, a composable lock-free library [1]. Now that OCaml 5 is released, we're reviving this work.
It's semantics is weaker than STM -- unlike STM, it doesn't provide serializability but Reagents can compile down to multi-word compare and swap operations, which can be implemented with the help of hardware transactions (when present) or efficient software implementations of it [2]. Hence, Reagent programs should be faster than STM.
Thanks for the reply. I hope that the array and list comprehensions land soon in upstream; it's a useful and hopefully not-too-controversial feature.
I'm more ambivalent regarding the local allocations and the unboxed types. I totally understand why they'd be useful when you are trying to squeeze every last drop of performance, but they do require a not-so-trivial complexification of the language.
The local types are less invasive than the full support for typed effects. In particular, they are opt-in and associated complexity is pay-as-you-go. In my initial experiments, they seemed pretty nice to program with.
I have used Jupyter notebooks with a Docker deployment in my prior courses for OCaml and Prolog, with support for auto grading (using nbgrader). Jupyter notebooks aren’t great for version control. Otherwise, it worked pretty well across multiple iterations of the course with new professors coming in and independently being able to use the infra.