How would you do lazi init of record fields in OCaml?

Is it possible to do lazy initialization of immutable record fields in OCaml?

If you don’t mind altering the type slightly, just use Lazy.t:

(* Basic version, normal initialisation *)
type t = { foo : foo }
let v = { foo = foo () }

(* With lazy *)
type t_lazy = { foo_lazy : foo Lazy.t }
let v_lazy = { foo_lazy = lazy (foo ()) }

It means that you have to use Lazy.force at the use points, but with OCaml 4.x it’s mostly free, and even with OCaml 5 it’s not that expensive.

2 Likes

Hm, ok. Do I have to use Lazy.force at each usage? Or only once?

You have to use Lazy.force every time (or a lazy pattern). These are the only ways to convert from foo Lazy.t into foo.

If it’s the heavy syntax that’s bothering you, you could try lazy patterns:

(* Normal record *)
let x = v.foo

(* With Lazy.force *)
let y = Lazy.force v_lazy.foo_lazy

(* Alternatives, both equivalent to the Lazy.force version *)
let y = match v_lazy with { foo_lazy = lazy foo } -> foo
let { foo_lazy = lazy y } = v_lazy

Although it’s only going to be lighter if you read several lazy fields at the same time.

1 Like

A slightly shorter variant would also be:

let lazy y = v_lazy.foo_lazy
4 Likes