What does Obj.size return?

There is no documentation for Obj.size. Can someone explain what the function returns exactly? It seems it can be used only on blocks.

Thanks!

Lets suppose you have a record:

type record ={a:int; b:int;c:int}
let r = {a=42;b=42;c=90}

You can have a representation of r with let obj = Obj.repr r. Then Obj.size obj will return 3 (since there are 3 values). And you can access the physical values with Obj.raw_field. Here, Obj.raw_field r 0 will return 85n (nativeint), since 42 is stored as 2n+1=85 in physical memory.

Note that Obj.size (Obj.repr ((34,78),(67,90)) ) will return 2 since you have a couple of 2 tuples, then in memory, 2 pointers.

Note, that from my trials, Obj.size crash when the 0 value should be returned. (With a type type t=A|B|C (the A, B, or C is not stored among the field) or simply the type unit (the ()value).

The Obj module is not meant to be used by casual users, which is why it is not documented.

To answer your question, you need to understand that every OCaml value is represented at runtime either as a word-size integer (ints, chars, bools, constants constructors, etc) or as a pointer to a memory block containing n fields (eg a record or tuple or constructor with n fields).

The function Obj.size returns the number of fields of a value, assuming it is represented at runtime as a block; it will probably crash if the value that you pass as argument is represented as an integer.

If you want to learn more about the runtime representaiton of values in OCaml:

Cheers,
Nicolas

2 Likes

Yes, you are right, with:

type t = A | B | C;;
let a = ref A;;
Obj.raw_field (Obj.repr a) 0;;

The result is 1n, which is an unboxed value. Obj.size does only work with blocks (pointers). (Things whose Obj.is_block ... returns true).

Just to add to the answers, here’s how I approach these questions.

Obj.size is implemented as a primitive in obj.mli:

Now if you grep for %obj_size, you will see that:

ocaml % git grep "%obj_size"
Binary file boot/ocamlc matches
lambda/translprim.ml: "%obj_size", Primitive ((Parraylength gen_array_kind), 1);
stdlib/obj.ml:external size : t -> int = "%obj_size"
stdlib/obj.mli:external size : t -> int = "%obj_size"

%obj_size is a primitive that gets compiled to the primitive Parraylength which gets the length of a generic array.

Given the uniform value representation, the length of an array applied to arbitrary heap blocks returns the number of fields in the block. The primitive Parraylength also assumes that the argument is at least a heap block (not necessarily an array) and hence, it crashes on immediate values.

% ocaml       
OCaml version 5.0.0
Enter #help;; for help.

Findlib has been successfully loaded. Additional directives:
  #require "package";;      to load a package
  #list;;                   to list the available packages
  #camlp4o;;                to load camlp4 (standard syntax)
  #camlp4r;;                to load camlp4 (revised syntax)
  #predicates "p,q,...";;   to set these predicates
  Topfind.reset();;         to force that packages will be reloaded
  #thread;;                 to enable threads

# Obj.(size (repr 5));;
zsh: segmentation fault  ocaml
5 Likes