Runtime representation
This page describes how OCaml values are represented at runtime in JavaScript. Understanding this is useful for debugging, writing JavaScript primitives, and understanding compatibility limitations.
Overview
Js_of_ocaml maps OCaml values to JavaScript values as directly as possible for performance. This differs from the standard OCaml runtime representation.
OCaml type | JavaScript representation |
| Number (32-bit) |
| Number (unboxed) |
| Number (0 or 1) |
| Number (0-255) |
| Special string object (MlBytes) or JavaScript string |
| Special bytes object (MlBytes) |
| JavaScript Array with tag |
| JavaScript Array with tag 0 |
| JavaScript Array with tag 0 |
| Number (constant) or Array (with arguments) |
| Number (32-bit) |
| Number (32-bit) |
| MlInt64 object |
| Ml_Bigarray object |
| Array with exception identity |
| Array with method table and instance variables |
Integers
OCaml integers are represented as JavaScript numbers. Unlike native OCaml where integers are 31 or 63 bits (with one bit used for tagging), js_of_ocaml uses the full 32-bit range.
Implications:
- Arithmetic behaves slightly differently at the boundaries
max_intandmin_inthave different values than native OCaml
Floats
OCaml floats are JavaScript numbers directly.
Implications:
- Better performance for float-heavy code
- Polymorphic hash and comparison may give different results than native
- Marshalled floats cannot be unmarshalled by the native OCaml runtime
Rounding difference: JavaScript rounds ties away from zero, while native OCaml (libc) rounds ties to even.
Booleans
OCaml booleans are represented as the numbers 0 (false) and 1 (true), not JavaScript's true and false. See type conversions for converting between them.
Bytes
OCaml bytes are always represented as MlBytes objects with:
t— tag indicating the encodingl— length in bytesc— contents (a JavaScript string or array of bytes)
The contents can be a JavaScript string (more memory efficient) or an array of bytes (for mutation). The runtime converts between these as needed.
Strings
OCaml strings can be represented as:
- A JavaScript string directly (when
--enable use-js-stringis set, which is the default) - An MlBytes object (above)
Important: Even when represented as a JavaScript string, it encodes a sequence of bytes, not UTF-16 text. Each character's code point represents one byte (0-255). Assuming the bytes are UTF-8 encoded text, use Js.string to convert to a native UTF-16 JavaScript string. To convert back, use Js.to_string. See conversions.
Blocks, arrays, records, modules
OCaml heap-allocated values (arrays, tuples, records, variant constructors with arguments) are represented as JavaScript arrays where:
- Index 0 contains the block tag
- Remaining indices contain the fields
For example, Some 42 becomes [0, 42] (tag 0, one field).
Variants
- Constant constructors (no arguments): represented as integers starting from 0
- Non-constant constructors: represented as arrays with a tag
type t =
| A (* 0 *)
| B (* 1 *)
| C of int (* [0, n] — tag 0, since it's the first non-constant *)
| D of int (* [1, n] — tag 1 *)Int32 and Nativeint
Int32.t and Nativeint.t are represented directly as JavaScript numbers, like regular int values.
Note that nativeint is 32 bits in js_of_ocaml (matching JavaScript's bitwise operations), not the platform's native word size.
Int64
Int64.t values are represented as MlInt64 objects, which store the value as three numbers: two 24-bit integers (lo, mi) and one 16-bit integer (hi), since JavaScript numbers cannot represent the full 64-bit range precisely.
Bigarray
Bigarrays are represented as Ml_Bigarray objects, which use JavaScript Typed Arrays for storing the underlying data:
OCaml kind | JavaScript Typed Array |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
Exceptions
OCaml exceptions are represented as:
- Without arguments: the exception identity directly (a unique object per exception type)
- With arguments: a JavaScript array where index 1 is the exception identity and remaining indices contain the arguments
For example, Not_found is just its identity object, while Failure "oops" becomes [0, <Failure identity>, "oops"] (index 0 is the block tag).
Note: OCaml exceptions are not JavaScript Error objects. When an OCaml exception propagates to JavaScript code, it appears as an array, not an Error. See error handling for how to work with exceptions across the OCaml/JavaScript boundary.
Objects
OCaml objects (from the object-oriented layer) are implemented using JavaScript arrays. They have nothing to do with JavaScript objects. Use the PPX syntax (object%js) to create JavaScript objects.
Compatibility considerations
Due to representation differences, some operations behave differently:
Marshalling (Marshal module):
- Output may differ from native OCaml
- Do not unmarshal js_of_ocaml output with native OCaml (especially floats)
- Marshalling between js_of_ocaml programs works correctly
Polymorphic comparison and hashing:
- Results may differ from native OCaml for floats
See also
- Type conversions — Converting between OCaml and JavaScript types
- JavaScript primitives — Writing custom primitives