Tarides Logo
A 3D render of a black laptop with large square icons popping out of the screen, including a red pie-chart-looking diagram, a purple one with a chart, a blue one with smaller squares on it, and a yellow and a green one with a geometric representation of image and text. The background is beige.

OCaml 5.4 Release: New Features, Fixes, and More!

Posted on Fri, 10 Oct 2025

It's everyone's favourite time of the year – the time for a new OCaml release! 5.4 brings improvements and optimisations as well as new features, some of which may be familiar to long-time members of the OCaml community. Today's post highlights some of the work done to improve the language for everyone. As always, we can't cover everything, and for a more exhaustive list, I recommend checking out the changelog in the OCaml repo.

Let's dive in!

Immutable Arrays

Immutable arrays, as their name suggests, are like regular arrays in OCaml, with the major difference that their contents cannot be modified after they are created. Immutability is often a useful property for data structures and extending this to arrays provides various improvements over regular arrays.

Immutable arrays can improve safety in cases where mutation isn't required and only random-access packed memory is needed. In such a situation, an immutable array clearly communicates the design intention to the developer, improving their use of the code and improving safety as a consequence. Since the immutability property does not allow a function to change the contents, immutable arrays also improve the reasoning properties of the code, which verification tools can use. More concretely, a new predefined type 'a iarray and an Iarray module (with corresponding Iarraylabels) have been added to the Stdlib.

Lastly, immutable arrays can be safely coerced since there's no risk of inserting incompatible types. Consider this code example:

module Positive : sig
  type t = private int
  val make : int -> t
end = struct
  type t = int
  let make i = if i > 0 then i else invalid_arg "make"
end

let nums = [1; 2; 3; 4; 5; 6]

let lst = List.map Positive.make nums
let arr = Array.of_list lst
let iarr = Iarray.of_list lst

You can sum up lst with List.fold_left (+) 0 (lst :> int list), but if you do that with Array.fold_left (+) 0 (arr :> int array) you will be told Type Positive.t array is not a subtype of int array. Conversely, Iarray.fold_left (+) 0 (iarr :> int iarray) works, which is very useful, as the only workaround with an array is to coerce individually or - more often - copy the items to a new array, which is unfortunate (because the copy is just to satisfy type safety).

Pull Request #13097 introduced immutable arrays to OCaml 5. It is a feature Jane Street has been using internally in their OxCaml branch. The team at Tarides collaborated with Jane Street engineers to upstream this feature. The resulting PR sparked some great discussions in the community, and after considering their feedback, it was merged to form part of the 5.4 release.

Labelled Tuples

Labelled tuples allow the developer to label tuple elements, giving useful names to constructed values in cases where labelled function arguments allow them to name parameters. Reordered and partial patterns are resolved during type checking, and the labels are erased during translation to lambda. Labelled tuples do not support extracting an element of the tuple by the label.

One example of this being useful is when developers want to compute two values from a list without mixing them up. Labelled tuples can help prevent them from accidentally returning the pair in the wrong order or mixing up the order of the initial values. This code was given as a motivating example by the authors:

let sum_and_product ints =
  let init = ~sum:0, ~product:1 in
  List.fold_left ints ~init
    ~f:(fun (~sum, ~product) elem ->
          let sum = elem + sum in
          let product = elem * product in
          ~sum, ~product)

The function ~f has type sum:int * product:int -> int -> sum:int * product:int which enforces the ordering when constructing the return tuple.

Jane Street has been using labelled tuples internally for almost a year as part of their OxCaml branch, and reports that it has been a useful and popular feature. A core developer, David Allsopp, also benefited from it when he was working on the Relocatable OCaml Project. He used labelled tuples in the test harness for the feature.

To find out more, check out Chris's talk from the 2024 ML workshop, the ML workshop talk proposal, and PR #13498, which documents the changes.

Frame Pointers

Frame pointers are used to walk the stack of function calls in a program. Tools like profilers and debuggers use frame pointers to walk the stack and reconstruct the call graph for programs. Having this support means that third-party debugging and performance tools, like perf, eBPF, Dtrace, GDB, and LLDB now work much better with OCaml.

The history of frame pointers in OCaml is a long and somewhat complicated one. The compiler has had an option for frame pointers on AMD64 since OCaml 4.01, released in 2013. After the multicore update in OCaml 5, support returned for Linux/AMD64 (#11144) in the 5.1 release and macOS/AMD64(#13163) in the 5.3 release. In 5.4, support was added for ARM64 on both Linux and macOS, along with documentation on using frame pointers to profile OCaml code. The team has started work on supporting RISC-V, s390x, and Power architectures, which we hope to see implemented in the future.

For a fuller view of all the work, you can check out PRs #13500, #13575, #13635, and #13751, which have improved frame pointer support in OCaml 5.4. Tim McGilchrist also wrote a blog post on his website about implementing frame pointers in OCaml.

Atomic Field Accesses

Previously, OCaml 5 had limited support for atomic operations, only supporting them on the special 'a Atomic.t type. After a lot of discussion on the best solutions, consensus landed on introducing records with atomic fields to improve performance when implementing concurrent data structures. Instead of requiring a field to be of type 'a Atomic.t and introduce an indirection on that record field, having records with atomic fields is more efficient.

PR #13404 implements atomic operations, including two features described in 'atomic record fields' RFC. First, atomic record fields are now just record fields marked with an atomic attribute, and their reads and writes are compiled into atomic operations. Second, the PR implements atomic locations, a compiler-supported way to describe an atomic field within a record to perform atomic operations in addition to read and write operations.

Unloadable Runtime

OCaml 5.4 reintroduces 'memory cleanup upon exit' mode. The purpose of this mode is to enable something called the 'unloadable runtime'. Suppose you're running a program written in another programming language, and you use an OCaml library as a shared library. When control switches over from the OCaml library to the main program, you want the handover to happen cleanly, with all OCaml runtime resources being 'unloaded', including the stack, heap sections, code fragments, custom operations, buffers, and tables.

In the update from OCaml 4 to 5, support for the unloadable runtime was lost as multiple domains complicated matters. An OCaml program generally stops and exits once the main domain runs to completion, and the same behaviour needs to be adopted for multiple domains. When the main domain stops, the other domains are also terminated. Terminating all running domains was the trickiest aspect to implement since only stopping for garbage collection was originally supported. Now, with 'memory cleanup upon exit' mode, all domains can be terminated, and the runtime can be unloaded before control is handed back, ensuring a clean handover to a host program. Learn more in PR #12964, which introduced the feature in 5.4.

… And Many More!

GC Performance Improvements (Stephen Dolan, Nick Barnes, Gabriel Scherer, reviews by François Bobot, Josh Berdine, Damien Dologez, Tim McGilchrist, Guillaume Munch-Maccagnoni, benchmarking by Nicolás Ojeda Bär, and reports by Emilio Jesús Gallego Arias and Olivier Nicole)

This project improved the performance of garbage collection in the runtime. Changes to the way ephemerons are treated by the minor GC, allowing values from ephemeron keys to be collected and optimising them so they are not re-marked, have expanded their functionality whilst keeping the minor GC performant. A change to the major GC’s pacing, fixing a bug where the work_counter would get out of sync with the alloc_counter, also boosted performance. Finally, a new Gc.ramp_up callback will be introduced, allowing users to mark ramp-up phases of memory consumption and preventing slowdowns as a result of collection work being done twice. The work is spread across several PRs, including #13643, #13827, #13736, #13300, and #13861.

Software Prefetching Support (Tim McGilchrist, review by Nick Barnes, Antonin Décimo, Stephen Dolan and Miod Vallat)

5.4 enables software prefetching instructions for several architectures, including ARM64, s390x, PPC64, and RISC-V. This feature advises the processor to 'pre-fetch' data from slower memory and store it in faster memory before it is needed. This can help improve the overall performance of programs, and in fact, the PR #13582 contains several benchmarks showing speed-ups as a result of the changes.

Review of Locking in the Multicore Runtime (Guillaume Munch-Maccagnoni, review by Gabriel Scherer, tests by Jan Midtgaard)

Part of the task between updates is to identify and address problems. In PRs #13227 and #13714, issues surrounding the caml_plat_lock_non_blocking and caml_plat_lock_blocking caused deadlocks in the runtime. After auditing and testing the code to see what was going wrong, tighter constraints about when and how the commands could be mixed helped solve the deadlocking.

Polymorphic Parameters (Ulysse Gérard, Leo White, review by Florian Angeletti, Samuel Vivien, Gabriel Scherer and Jacques Garrigue)

This is another upstreamed feature from Jane Street's OxCaml branch. The polymorphic parameters extension lets users have function parameters with polymorphic types, only requiring a type annotation on the function parameter. PR #13806 goes into more detail on the implementation, including the introduction of a new invariant and how to use polymorphic parameters.

A Few Bug Fixes

#13605 (Samuel Vivien, review by Florian Angeletti, Richard Eisenberg and Jacques Garrigue)

This PR adds a check to detect and prevent errors occurring as a result of generating typing constraints. When users define a parametrised type and create a constraint by binding that type with an as, there were times when a constraint would not behave as expected. By adding an error, this PR prevents users from having constraints and introduces unwanted behaviour.

#13812 (Samuel Vivien, review by Gabriel Scherer)

This PR adds another check that tests the validity of the type variable name on the right-hand side of _as_. The added test reduces friction and confusion for the user.

#13895 and #13691 (Jan Midtgaard, review by Miod Vallat, Sadiq Jaffer and Antonin Décimo)

Gc.control had four underlying globals that would cause data races when tested with TSan. Jan tested them and rewrote them to be atomic, which resolved the racing and brought them in line with other globals which were already atomic.

What’s Next?

Work continues! Performance improvements to the garbage collector that aim to reduce the performance gap between versions 4.14 and 5.x include GC pacing and mark delay work. Relocatable OCaml is another ongoing project, whose RFC was accepted in principle in March. It wasn't quite ready for 5.4, but will hopefully finally be arriving in OCaml 5.5!

You can connect with us on Bluesky, Mastodon, Threads, and LinkedIn or sign up for our mailing list to stay updated on our latest projects. We look forward to hearing from you!

Open-Source Development

Tarides champions open-source development. We create and maintain key features of the OCaml language in collaboration with the OCaml community. To learn more about how you can support our open-source work, discover our page on GitHub.

Explore Commercial Opportunities

We are always happy to discuss commercial opportunities around OCaml. We provide core services, including training, tailor-made tools, and secure solutions. Tarides can help your teams realise their vision