Weak (object refs/ptrs) in OCaml?

Here, by “reference”, I’m referring to the Java sense of the word, not the OCaml {mutable contents: 'a} trick.

Does OCaml support weak refs/ptrs ? What I found via google is OCaml library : Weak this is a bit weird, as the primitive of Array of weak ptrs or HashSets of weak ptrs; whereas I just want a primitive that is a WeakPtr itself.

The API for a 'a WeakPtr would be some function get: 'a WeakPtr -> 'a option


Wouldn’t it be simple to use an 'a Weak.t singleton array as a single value?

Do you not find it slightly weird that

  • the primitive for a Weak-ref is NOT a singleton Weak-ref

  • the primitive for Weak-ref is an ARRAY OF Weak-ref ? [not shouting, emphesis]

Is there a story behind this due to the way values are represented in OCaml; how GC is done, and how due to the GC friendly representation, … (I have no evidenced ,just guessing here)

I believe the reason is simple: it is not possible to store a weak pointer in a normal array without incurring a potential memory leak, as the weak pointer will be left in the array even if it becomes “empty”; so a set (or table) of weak pointers is the better primitive.


In Rust, the solution is something like promote :: 'a Weak -> 'a Strong option

This avoids the leak issue in that weaks don’t prevent objects from being gc-ed

I don’t get how an array of weak-ref is useful in this case. We have an array of weak-ref; one of the item gets gc-ed.

What happens now for the weak-ref in the atrray? Is it not a “dangling ptr” or does it automatically vanish behind our back (i.e. the length of the array suddenly shrinks).

Clearly I’m misunderstanding something, but it is not obvious to me how this solves anything.

I wasn’t very clear, let me try again. My mental model is that a “weak pointer” looks like 'a option ref (except that the reference has weak semantics). A normal array of such objects then looks like 'a option ref array. By contrast, a “weak array” ('a Weak.t) looks like 'a option array (again, with weak semantics). You can see that a “weak array” occupies less space and has better data locality (one less indirection to reach the data) than a (normal) array of “weak pointers”. Since you can define a “weak pointer” as a “weak array” of size 1, the latter seems the better primitive.



Does 'a take less space than 'a ref ?

If yes: This shows my lack of OCaml internals knowledge, but this is not obvious to me. I would expect a compiler to be able to optimize the {mut contents: 'a} indirection away.

If no: how are you making the argument that 'a option ref array is more expensive than a 'a option array ?

Yes. The OCaml compiler does not perform “unboxing” optimizations (having a uniform runtime representation of values is useful to implement polymorphism).

An understanding of the runtime representation of values is rather helpful to develop an intuition of how OCaml programs execute; I suggest learning about it. There are several good sources for this material:


1 Like

The work on unboxing in OCaml has been going for a long time, see e.g. Unboxed Types for OCaml talk from 2019. There’s a working (production-tested) implementation JaneStreet fork of OCaml and it’s been gradually upstreamed but I don’t know the details.

See this RFC on unboxed types. It states:

OCaml currently has two attributes that this proposal may easily be confused with:

  • We can mark arguments to external calls as [@unboxed], as documented in the manual. This proposal essentially takes this idea and expands it to be usable within OCaml itself, instead of just at the foreign function interface boundary.
  • We can mark some types as [@@unboxed], as briefly described in a bullet point in this manual section. This attribute, applicable to a type holding one field of payload (either a one-field record or a one-constructor variant with one field), means that no extra box is allocated when building values of that type. It is notionally separate from this proposal, though there is an interaction: see the section mentioning [@@unboxed] in its title.

AFAIR the longest-available form of unboxing in OCaml is the Lazy.t type, where the value is unboxed after the lazy is forced IIRC.