OCaml Local Variables, Return Values and Regions

A worked example shows how `local_` and `exclave_` let a function accept a local value and return a local structure in its caller's region.

Channel
Jane Street
Published
Jan 23, 2024
Video
12:52
Read
4 min
Slides
7
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

In the second OCaml Unboxed lesson on experimental locals, the speaker extends local annotations from parameters to variables and return values. Compiler examples show escape errors, special treatment of tail positions, and how `exclave_` and a local return annotation allow a greeting list to be allocated in the caller's region.

  1. 1Local variables cannot escapeAssigning local `x` into a longer-lived string reference produces an escape error.
  2. 2A local tuple can contain localsThe compiler infers that a tuple containing local values is local when the tuple itself does not escape.
  3. 3Tail positions are specialThe same `ignore` call can fail in return position; the speaker defers the detailed rules.
  4. 4A helper needs locality in its typeAn ordinary `string -> string list` signature does not promise that its argument stays local.
  5. 5End the region early`exclave_` makes the greeting list part of the outer region, while `local_` on the return communicates the calling convention and result locality.
  6. 6Parameters and local aliases differThe example compiler permits the parameter in the exclave but rejects a local alias defined inside the function.

Takeaways

  1. A local variable cannot escape its region, including through a longer-lived reference.
  2. A structure containing local values can itself be local if it does not escape.
  3. Return or tail positions have special locality rules that the speaker leaves for a later lesson.
  4. `exclave_` ends a function's region early so the following expression can allocate in the outer region.
  5. A local return annotation signals possible allocation in the caller's region and a result that must not escape it.
  6. In the example, a local parameter can be used inside an exclave, while a locally bound alias cannot.
FULL TEXT

Read the edited text by chapter

Transcript only
01

Local variables and escape

The speaker reviews local parameters and adds a local variable to an imperative function. Storing it in a reference produces an escape error.

Last time we saw a local parameter: the value received as an argument does not escape its region, so the function does not store it or put it in a structure that will be stored elsewhere. Today I want to generalize that to local variables and explain why we might need a local return value.

I'll start with a small imperative function of type `unit -> unit` and bind `x` using `let local_ x = "you"`. The annotation tells me that even if the function contains complicated imperative code, it cannot store this local value somewhere that lets it escape.

For example, I create a string reference outside the function and try to assign `x` to it. The compiler reports that the value escapes its region, exactly as the local annotation should prevent. Removing the assignment restores the working program.

A local value and a reference
SLIDE 1 / 7A local value and a referenceThe example tries to store local `x` in an outer reference, illustrating an escape.
02

Ignoring locals and tail positions

The experimental compiler needs a locally typed `ignore` in this example, and it can infer a local tuple. Return positions follow special rules that will be explained later.

Even using the built-in `ignore x` gives an escape error in the experimental compiler shown here: the built-in function does not yet know about locals. I define another `ignore` with type `local_ 'a -> unit`, and the program works. This feature is under development, so there are still rough edges.

I add another local variable `y` and pass `(x, y)` to the local-aware `ignore`. Neither value escapes merely because it is placed in a tuple: the tuple itself does not escape. The compiler infers that the structure containing the locals must itself be local.

A tuple containing local values
SLIDE 2 / 7A tuple containing local valuesA local-aware `ignore` accepts the tuple when it does not escape.
An escape error in tail position
SLIDE 3 / 7An escape error in tail positionThe same call in return position triggers a locality error in the demonstrated compiler.

There is a complication if I put `ignore (x, y)` directly in the function's return position: the compiler reports an escape. Return positions, also called tail positions, have special locality rules. I will explain those rules in a future video; for now I move the call out of return position and return `()` afterward.

03

Refactoring a greeting function

A helper that builds a list reveals why parameter and return locality matter. The initial signatures allow or cause escapes.

Next I build local greeting lists for `x` and `y`, each containing `"Hello,"` and the corresponding value. The code works, but it repeats the same operation. To avoid duplication I extract a helper `greet` taking a string and returning a string list.

Calling the helper with local `x` fails. Its ordinary type, `string -> string list`, says nothing that promises the argument will not be stored somewhere or otherwise escape. Marking the parameter `local_` makes that promise, but then the compiler reports another error: the implementation puts the local parameter into a list that it returns.

An ordinary helper cannot accept the local value
SLIDE 4 / 7An ordinary helper cannot accept the local valueThe compiler rejects `greet x` because the original function signature does not promise locality.
Returning a local parameter in a list
SLIDE 5 / 7Returning a local parameter in a listAfter marking the parameter local, the list return produces another escape error.

What I want is for the list to belong to the surrounding region rather than the helper's own region. The general rule is that a local value must not escape its region. Every function defines a region, and without a change, putting the local parameter into the returned list looks like an escape.

04

Exclaves and local returns

The speaker uses `exclave_` to end the helper's region before allocating the list in its caller's region. A local return annotation signals that allocation and prevents the result from escaping.

The keyword `exclave_` ends `greet`'s region early, before the list is constructed. The parameter `z` came from an outer region, so using it after the inner region ends does not make it escape that region. The newly constructed list is also allocated outside `greet`'s region, in the caller's region.

There is still an error until I mark the return as local. The compiler reports that a value escapes its region; I think that message is misleading in this case, although there is a good reason for the type error. The function must signal that it may allocate in its caller's region so the calling convention works.

A local return and `exclave_`
SLIDE 6 / 7A local return and `exclave_`The working signature and body allocate the list in the caller's region.

A `local_` return annotation communicates two things: the function may allocate in its caller's region, and the returned value is local and cannot escape that region. With both the annotation and `exclave_`, the example compiles. I can use `greet` for both local variables.

To recap, the local parameter permits `greet` to receive `x`; `exclave_` ends the helper's region before the list is built; and the local return annotation says the result is allocated locally in the parent and cannot escape further. The compiler knows that a parameter came from an outer region.

05

A local alias inside an exclave

A local alias of the parameter cannot be used inside the exclave in the example. The speaker notes that local parameters and local variables differ.

There is a subtle difference between a local parameter and a local variable. If I bind `let local_ a = z` inside `greet` and use `a` in the exclave, the compiler rejects it: the local variable cannot be used there. We have lost the fact that this binding came from the outer region. I'll explore the distinction further in a future video.

A local alias in the exclave
SLIDE 7 / 7A local alias in the exclaveThe example changes the returned list to use a locally defined alias, which the compiler rejects.

More from this channel

6 slides15:33EN
JSJane Street· Oct 26, 2026Figgie Strategy: Reading Hands, Winning Majorities and Pricing CardsBradley, Mike · Jane StreetJane Street traders Bradley and Mike analyze three games to show how private information, market competition and timing affect card prices.Decision MakingMathematicsFintech
1:48:29EN
JSJane Street· Oct 16, 2026How AI Is Changing Programming: John Krazit and Ron MinskyRon Minsky, John Krazit · Jane StreetJane Street’s AI tooling lead and the Signals and Threads host examine agent infrastructure, security, code review and the changing experience of writing software.Coding agentsDeveloper productivityEvals+2
1:36:37EN
JSJane Street· Sep 23, 2026Aaron Bauer on Teaching Software Engineering in the Age of AIRon Minsky, Aaron Bauer · Jane StreetHow learning goals, active practice and editor design shape engineering education when models can generate the code.AI in EducationSoftware engineeringEducation+2
9 slides1:05:45EN
JSJane Street· Sep 11, 2026Cyrus Omar on Live Programming and a Computational Commons for Humans and AICyrus OmarA demonstration of Hazel shows how immediate feedback, structured collaboration and carefully scoped permissions could support people and AI agents working together.Programming LanguagesHuman-AI CollaborationDeveloper workflows & testing+2
1:25:00EN
JSJane Street· Sep 2, 2026Eric Mannes on Turning Messy External Data Into Trading ResearchRon, Eric Mannes · Jane StreetFrom commodity futures and an Excel risk system to point-in-time datasets and AI, Eric Mannes explains the domain knowledge behind data engineering at Jane Street.Data quality & curationDeveloper workflows & testingInvesting+2
7 slides1:16:29EN
JSJane Street· Aug 26, 2026Grant Sanderson and Alok Puranik: Positional Encodings Through Group TheoryGrant Sanderson, Alok Puranik · 3Blue1BrownStarting with assumptions about attention, they derive matrix exponentials and connect rotations, decay and Jordan blocks to RoPE and ALiBi.Transformers & attentionMathematicsML fundamentals+1