OCaml -safe-string string literal sharing across separate modules
0 reputation · 01 Feb 2020, 17:26 UTC
0 reputation · 01 Feb 2020, 17:26 UTC
With -safe-string enabled by default since OCaml 4.06, strings are immutable and mutation lives in Bytes. The compiler may physically share identical literals inside a single compilation unit, but the language definition does not state whether the same literal in different modules maps to one heap object.
The objective is to establish whether == on string literals is a dependable cross-module identity check. The missing constraint is that separate compilation, inlining, and link order can change literal layout, so behavior may differ between a single executable and a dynamically loaded library.
Does the OCaml separate compilation model guarantee physical identity for identical string literals across modules? Which compilation flags or linking strategies influence whether literals are shared? Is an explicit interning table the only portable way to implement string identity?
34775 reputation · 01 Feb 2020, 19:37 UTC
No. OCaml separate compilation does not guarantee that identical string literals in different modules are the same heap object. With -safe-string enabled by default since OCaml 4.06, strings are immutable, but immutability is not the same as sharing. Comparing literals with == across module boundaries is therefore not a dependable identity check.
Separate compilation compiles each module independently. The compiler may emit the same literal once per object file, and the linker concatenates those tables without merging duplicate entries. A dynamically loaded library may keep its own copy of constants, so textually identical strings can be different heap objects.
This assumes OCaml 4.06 or later. Literal-table emission can vary between bytecode and native code, linker versions, and loading strategies. No OCaml flag is documented to force cross-module literal deduplication, so do not rely on link order or -O flags as a substitute for interning.
ocamlc -c m1.ml
ocamlc -c m2.ml
ocamlc -o test m1.cmo m2.cmo
./test
Let m1.ml and m2.ml each bind let s = "shared", then compare the two values with ==.
Use comments to ask for clarification. Post a solution as an answer.
34,775 reputation · 01 Feb 2020, 22:13 UTC
The OCaml language specification does not guarantee physical identity for identical string literals across separate modules. While the compiler may share literals within a single compilation unit to optimize memory, separate compilation units typically result in distinct heap objects for the same string literal when linked.
In native code, literals are usually stored in the rodata section of each object file. The linker does not necessarily deduplicate these across module boundaries, meaning that using == for cross-module identity checks is unreliable and can lead to unexpected behavior.
To implement reliable string identity across modules, you should use an explicit interning table (e.g., a Hashtbl or Map). This ensures that each unique string maps to a single memory address regardless of the module it was defined or used in.