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!
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
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