Richard Eisenberg: Using OCaml’s Coercion Operator

A practical tour of subtyping, polymorphic variants and private type abbreviations, with no runtime conversion cost.

RERichard EisenbergSpeaker · Jane Street
Channel
Jane Street
Published
Oct 1, 2024
Video
9:25
Read
2 min
Slides
3
Original
English
Open on YouTube
Scroll to read and the video shrinks to the bottom-right corner. Captions follow your reading language.
Reading languageAvailable in 2 languages
You're reading the original English.
SUMMARY

In 30 seconds

Richard Eisenberg demonstrates OCaml’s built-in coercion operator using polymorphic variants, recursive types and lists. He then uses a private integer abbreviation to show how a module can control construction while allowing values to be viewed as integers.

  1. 1Variant subtypingEvery value of a narrower polymorphic variant can be a value of a compatible wider variant.
  2. 2No runtime conversionA list coercion is checked by the type system and does not walk or reallocate the list at runtime.
  3. 3Private representationsA private integer abbreviation lets a module enforce an invariant at construction while allowing coercion back to int.

Takeaways

  1. OCaml can coerce between types when its subtype relation permits it.
  2. Polymorphic variants with compatible tags and payloads provide a subtyping example.
  3. Coercions can work through recursive types and lists without runtime traversal or allocation.
  4. A private abbreviation can expose a representation while restricting construction and preserving an invariant.
FULL TEXT

Read the edited text by chapter

Transcript only
01

Coercion and polymorphic variants

Eisenberg introduces the built-in coercion syntax with a narrow and a wider variant. He demonstrates why payloads must be compatible.

I want to explore OCaml’s subtyping relation and coercion operator. This is a feature of ordinary OCaml, rather than a Jane Street-specific extension, and it has been available for some time.

Some OCaml types have values that form a subset of another type’s values. Consider polymorphic variants: a type foo containing only the tag `Foo and a type foo_bar containing `Foo or `Bar. Every foo value is also a valid foo_bar value.

The expression `(x : foo :> foo_bar)` asks the compiler to check whether every value of the source type is valid for the target. If the check succeeds, the expression has the target type. When the source type is already known, it can be omitted; I will use the explicit form to make the examples clear.

Coercing a narrower polymorphic variant
SLIDE 1 / 3Coercing a narrower polymorphic variantThe source type contains only `Foo; the target also permits `Bar.

This is a built-in coercion operator, not a user-defined conversion. It only works when the actual definitions satisfy the subtype relationship. If `Foo carries an integer in the source but not in the target, the coercion fails; adding the corresponding integer payload to the target makes the example work again.

In this example the compiler’s error mentions the missing `Bar tag, which is true but is not the reason for failure. The incompatible integer payload is the important issue. The relationship also works recursively when the payloads themselves use compatible recursive types.

02

Recursive types and lists

The subtype relationship can extend through recursive definitions and lists. The coercion is a type check with no runtime conversion.

The coercion can go deeper: a foo list can be viewed as a foo_bar list. Unlike a conventional conversion that traverses and rebuilds a list, this operator is guaranteed to have no runtime effect. The compiler checks and changes the type, but the list is not reallocated or walked.

A list coercion
SLIDE 2 / 3A list coercionThe example widens a list’s variant type without rebuilding the list.
03

Private type abbreviations

A private integer abbreviation supports a construction invariant. Coercion exposes the representation in one direction without permitting arbitrary integers to become the private type.

Another application is a private type abbreviation. A module can declare `type t = private int` while implementing t as an integer. It can provide a constructor that accepts only positive values, giving the module control over an invariant while exposing the underlying representation.

The private type and int are distinct: using a t directly where an int is expected, or an int where a t is expected, does not type-check. But the coercion operator allows a t to be viewed as an int. It works under lists as well, so a list of t can be coerced to an int list without runtime work.

Private integers and list coercion
SLIDE 3 / 3Private integers and list coercionThe module checks positivity when constructing t, while callers can coerce a t list to an int list.

The reverse coercion is rejected. Allowing an arbitrary int to become t would bypass the positive-value invariant. The module controls construction of t values, while callers can inspect them through the exposed integer representation.

The same operator also works with object types. In the next video I will explore how coercion interacts with variance annotations on new data types.

More from this channel

1:34:29EN
JSJane Street· Jun 24, 2026Jacob Baskin on Building Superstore and Scheduling the HiveYaron Minsky, Jacob Baskin · Jane StreetThe Jane Street engineer traces the design choices behind a distributed analytical database and the challenge of allocating a growing research cluster.Infrastructure & deploymentSoftware engineeringDecision Making+1
1:34:36EN
JSJane Street· Jun 1, 2026Nate Foster: Treating the Network as a ProgramYaron Minsky, Nate Foster · Jane StreetFrom programmable switches to BGP, a programming-languages researcher explains how higher-level policies and formal models can make networks easier to change.Infrastructure & deploymentProgramming LanguagesSoftware engineering+2
5 slides15:48EN
JSJane Street· May 15, 2026Inside Jane Street’s Texas AI Data CenterDwarkesh Patel, Yaron Minsky, Daniel Pontecorvo · Dwarkesh PatelDwarkesh Patel tours a 4,032-GPU training facility with Ron Minsky and Dan Pontecorvo, examining liquid cooling, power distribution and operational safeguards.Infrastructure & deploymentAI cost & performance
1:48:21EN
JSJane Street· Mar 17, 2026Will Wilson on Deterministic Simulation and the Hard Problems of Software TestingYaron Minsky, Will Wilson · Jane StreetThe Antithesis co-founder explains how replayable simulations explore complex software, why properties matter and where testing meets its limits.Developer workflows & testingSoftware engineeringCode review & verification+2
7 slides1:20:57EN
JSJane Street· Dec 23, 2025Matt Godbolt: Inside Skylake’s Out-of-Order PipelineMatt GodboltA guided tour of instruction decoding, register renaming, execution and memory ordering, grounded in reverse engineering and careful measurements.SemiconductorsSoftware engineeringBenchmarks
9 slides55:03EN
JSJane Street· Oct 29, 2025Neil Mitchell: How Pyrefly Checks Python at ScaleNeil Mitchell, Roman · MetaA tour of Python's type system and the incremental architecture behind a fast, open-source checker and language server.Software engineeringOpen-source ecosystems