Tracks purescript-lua/purescript-lua-prelude#15 in this tracker.
Problem
The prelude's unit = {} is a reference-typed value: it allocates, carries object identity, and therefore needs the @inline unit never pin (prelude v7.3.1) to stay a shared singleton — the compiler must actively refrain from inlining it, and one dropped pragma away it reallocates per use site. FFI-produced units were never the shared table anyway (foreign modules cannot reference the prelude binding), so identity was already unreliable ecosystem-wide.
Approach
Fix lives in the fork (purescript-lua/purescript-lua-prelude#15): unit = "unit" — an interned scalar is a natural singleton (string interning makes every literal occurrence one object per VM) with zero per-use allocation, purerl's unit-atom move translated to Lua. The pragma flips to @inline unit always, so the binding dissolves and sites carry the literal:
-- today, with the never pin:
local Data_Unit_unit = ({}) -- shared, every use reads the binding
-- after:
-- no binding at all; every site is the literal "unit"
No compiler change is needed: lib/ is representation-agnostic (no reference to Data.Unit anywhere).
Prerequisites / Relations
Verification / Measurement
On the package-set bump: eval goldens stay byte-identical (they are the check that Array Unit printing survives the representation change); structural goldens churn only where the unit binding/accessor dissolves from linked output. The deterministic TNEW/TDUP census (bench/ci) must not grow at any affected artifact.
Tracks purescript-lua/purescript-lua-prelude#15 in this tracker.
Problem
The prelude's
unit = {}is a reference-typed value: it allocates, carries object identity, and therefore needs the@inline unit neverpin (prelude v7.3.1) to stay a shared singleton — the compiler must actively refrain from inlining it, and one dropped pragma away it reallocates per use site. FFI-produced units were never the shared table anyway (foreign modules cannot reference the prelude binding), so identity was already unreliable ecosystem-wide.Approach
Fix lives in the fork (purescript-lua/purescript-lua-prelude#15):
unit = "unit"— an interned scalar is a natural singleton (string interning makes every literal occurrence one object per VM) with zero per-use allocation, purerl'sunit-atom move translated to Lua. The pragma flips to@inline unit always, so the binding dissolves and sites carry the literal:No compiler change is needed:
lib/is representation-agnostic (no reference toData.Unitanywhere).Prerequisites / Relations
neverpin unnecessary for correctness, while this change removes the shared value entirely (the better endpoint).Verification / Measurement
On the package-set bump: eval goldens stay byte-identical (they are the check that
Array Unitprinting survives the representation change); structural goldens churn only where the unit binding/accessor dissolves from linked output. The deterministic TNEW/TDUP census (bench/ci) must not grow at any affected artifact.