{0 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.

{1:overview Overview}

Js_of_ocaml maps OCaml values to JavaScript values as directly as possible
for performance. This differs from the standard OCaml runtime representation.

{t
 | OCaml type | JavaScript representation |
 | [int] | Number (32-bit) |
 | [float] | Number (unboxed) |
 | [bool] | Number (0 or 1) |
 | [char] | Number (0-255) |
 | [string] | Special string object (MlBytes) or JavaScript string |
 | [bytes] | Special bytes object (MlBytes) |
 | [array] | JavaScript Array with tag |
 | [tuple] | JavaScript Array with tag 0 |
 | [record] | JavaScript Array with tag 0 |
 | [variant] | Number (constant) or Array (with arguments) |
 | [int32] | Number (32-bit) |
 | [nativeint] | Number (32-bit) |
 | [int64] | MlInt64 object |
 | [bigarray] | Ml_Bigarray object |
 | [exception] | Array with exception identity |
 | [object] | Array with method table and instance variables |
}

{1:integers 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.

{b Implications}:
- Arithmetic behaves slightly differently at the boundaries
- [max_int] and [min_int] have different values than native OCaml

{1:floats Floats}

OCaml floats are JavaScript numbers directly.

{b 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

{b Rounding difference}: JavaScript rounds ties away from zero, while native
OCaml (libc) rounds ties to even.

{1:booleans Booleans}

OCaml booleans are represented as the numbers 0 ([false]) and 1 ([true]),
not JavaScript's [true] and [false]. See
{{!page-"javascript-interop".conversions}type conversions}
for converting between them.

{1:bytes Bytes}

OCaml bytes are always represented as MlBytes objects with:
- [t] — tag indicating the encoding
- [l] — length in bytes
- [c] — 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.

{1:strings Strings}

OCaml strings can be represented as:
- A JavaScript string directly (when [--enable use-js-string] is set, which is the default)
- An MlBytes object (above)

{b 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 {{!page-"javascript-interop".conversions}conversions}.

{1:blocks 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).

{1:variants Variants}

- {b Constant constructors} (no arguments): represented as integers starting from 0
- {b Non-constant constructors}: represented as arrays with a tag

{@ocaml[
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 *)
]}

{1:int32 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.

{1:int64 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.

{1:bigarray Bigarray}

Bigarrays are represented as Ml_Bigarray objects, which use JavaScript Typed
Arrays for storing the underlying data:

{t
 | OCaml kind | JavaScript Typed Array |
 | [Float32] | [Float32Array] |
 | [Float64] | [Float64Array] |
 | [Int8_signed] | [Int8Array] |
 | [Int8_unsigned] | [Uint8Array] |
 | [Int16_signed] | [Int16Array] |
 | [Int16_unsigned] | [Uint16Array] |
 | [Int32] | [Int32Array] |
 | [Int64] | [Int32Array] (2 elements per value) |
 | [Int] | [Int32Array] |
 | [Nativeint] | [Int32Array] |
 | [Complex32] | [Float32Array] (2 elements per complex) |
 | [Complex64] | [Float64Array] (2 elements per complex) |
 | [Char] | [Uint8Array] |
}

{1:exceptions Exceptions}

OCaml exceptions are represented as:
- {b Without arguments}: the exception identity directly (a unique object per exception type)
- {b 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).

{b 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 {{!page-"errors"}error handling} for how to work with exceptions
across the OCaml/JavaScript boundary.

{1:objects Objects}

OCaml objects (from the object-oriented layer) are implemented using JavaScript
arrays. They have nothing to do with JavaScript objects. Use the
{{!page-"ppx"}PPX syntax} ([object%js]) to create JavaScript objects.

{1:compatibility Compatibility considerations}

Due to representation differences, some operations behave differently:

{b 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

{b Polymorphic comparison and hashing}:
- Results may differ from native OCaml for floats

{1 See also}

- {{!page-"javascript-interop".conversions}Type conversions} — Converting between OCaml and JavaScript types
- {{!page-"linker"}JavaScript primitives} — Writing custom primitives
