Hmm... I see your point. But then how would I be able to store an object's address? (perhaps, the solution would be to use no GC whatsoever which is pretty much what I'm doing?)
Btw... here is an experimental implementation of NaN-tagging I've just written (roughly based on this article: [https://nikic.github.io/2012/02/02/Pointer-magic-for-efficient-dynamic-value-representations.html)](https://nikic.github.io/2012/02/02/Pointer-magic-for-efficient-dynamic-value-representations.html\)). I believe it's working though I haven't had time to thoroughly test it. **Code:** import bitops type ObjType = enum strObj, arrObj Obj = ref object case kind: ObjType: of strObj: s: string of arrObj: a: seq[Obj] Val {.final,union,pure.} = object asDouble: float64 asBits: int64 const MaxDouble = cast[int64](0xfff8000000000000) const Int32Tag = cast[int64](0xfff9000000000000) const PtrTag = cast[int64](0xfffa000000000000) proc newVal(num:int64): Val {.inline.} = Val(asBits: bitor(num,Int32Tag)) proc newVal(num: float64): Val {.inline.} = Val(asDouble:num) proc newVal(obj: Obj): Val {.inline.} = Val(asBits: bitor(cast[int64](obj),PtrTag)) proc isDouble(v: Val): bool {.inline.} = v.asBits < MaxDouble proc isInt32(v: Val): bool {.inline.} = bitand(v.asBits,Int32Tag) == Int32Tag proc isObj(v: Val): bool {.inline.} = bitand(v.asBits,PtrTag) == PtrTag proc getDouble(v: Val): float64 {.inline.} = v.asDouble proc getInt32(v: Val): int32 {.inline.} = cast[int32](bitand(v.asBits,bitnot(Int32Tag))) proc getObj(v: Val): Obj {.inline.} = result = cast[Obj](bitand(v.asBits,bitNot(PtrTag))) let a = newVal(32) echo a.getInt32() let b = newVal(34.53) echo b.getDouble() let c = newVal(Obj(kind:strObj, s:"hello")) echo c.getObj().s Run **Output:** 32 34.53 hello Run
