Tagged multi-schema storage with checked access and reassignment.
Variant
Construct with a schema list in tuple form, for example (Int32 Nat8) Variant.
Variant
(alternatives -- variant) Constructs an owning tagged-storage object, selects tag 0, and initializes that alternative according to its lifetime rules.- Use a nonempty
ListorTupleof alternative-schema objects, such as (Int32Nat8). Their schemas and views describe the alternatives; their stored prototype values are not copied into the payload. - Named Struct fields are also accepted and are indexed by ordinal.
- The object owns its active alternative.
INITselects tag 0 and initializes that alternative; normal destruction runs the destruction operation for the alternative selected by its valid tag.
Remarks
- A managed prototype with an
INIToperation initializes according to that operation rather than copying its stored value. AnINITfield without a managed lifetime does not change initialization. - Alternatives need supported storage size and alignment. Direct
TextandCodealternatives are not supported. An accessed alternative must not be Meta.
Fields
VARIANT: static emptyTuplemarker.typeList: static NILRefdescriptor for the alternative collection, not a stored copy of its values.maxSize: staticInt32byte count, at least 1.maxAlignment: staticInt32byte count, at least 1.typeTag:Int32zero-based alternative ordinal.memory: oneNat8,Nat16,Nat32, orNat64selected by payload alignment.filler:Nat8array of lengthmaxSize - maxAlignment.
Layout
- Variant stores its
Int32tag before the suitably aligned payload. Total size includes the tag, alignment padding, and possible tail padding; total alignment is at least theInt32alignment. - All measurements are target-dependent. Query
storageSizeandalignmentfor whole-object layout; do not substitute the maximum payload measurements. - The
String/Int32case has Variant/Union sizes24/16on 64-bit targets and16/12under-32bits.
Methods
rawInit
(--) Initializes the alternative selected by the current valid tag without changing that tag.Remarks
- Use only when that alternative's storage is not already live; initializing over a live owned value can lose its resources.
rawDestroy
(--) Destroys the alternative selected by the current valid tag without changing that tag.Remarks
- Do not destroy the alternative twice; restore a valid initialized state before normal destruction of the Variant.
- The result is an object, not a reference.
setTag
(key --) Changes the active alternative when key differs from the stored tag.keymust be anInt32. It accepts a known or unknown key and does not check the range; an unsupported key is stored without initializing an alternative.- When key equals the current tag, the existing payload is unchanged. Otherwise the old alternative is destroyed, key is stored, and the new alternative is initialized.
getUnchecked
(key -- ref) Returns a borrowed typed view of storage for key without checking the stored tag.keymust be anInt32ordinal.- No tag check is performed; the caller must ensure that the requested alternative is valid to access. An unknown key requires uniform alternative schemas. Unknown-key bounds are the caller's responsibility. Use
visitto dispatch typed access to heterogeneous alternatives when the tag is unknown.
get
(key -- ref) Returns the selected storage view after checking that key equals the stored tag.- A known mismatch is a compile-time error,
Wrong tag in Tagged Union!, in either DEBUG mode. - An unknown mismatch reports
Wrong tag in Tagged Union!and exits with status2when DEBUG is enabled. With-ndebug, the runtime tag check is omitted. - The caller must still ensure that the requested alternative is valid to access.
- The same
Int32ordinal and knownness requirements asgetUncheckedapply.
assign
(value key --) Selects key and assigns value to that alternative.valuemust have the selected alternative's schema. Assignment requires the relevant copy/move support and follows the input view's rules; a mutable managed input can be moved from, while an immutable input is copied.- A tag change destroys the old alternative before initializing and assigning the new one.
visitInternal
(... branches offset -- ...) Applies visit's dispatch rules starting at the specified known Int32 field offset in branches.offsetmust identify the start of the intended remaining key/callable sequence, its final fallback, or the end of the collection.branches 0 visitInternalis equivalent tobranches visit.
visit
(... branches -- ...) Dispatches the branch selected by the active tag.branchesis one Struct containing alternatingInt32keys and call-supported branch objects, optionally followed by one fallback. Keys used to access heterogeneous alternatives must be known.- The first matching key wins. Its branch receives the payload view that
getwould return for its key on top of the caller's remaining stack. The fallback receives no payload. - If no key matches and no fallback exists, nothing is called; an empty collection is a no-op.
- Branch calls may consume the carried stack and return additional objects. A
Blockbranch has a call boundary. - When match comparisons decide dispatch during compilation, only the selected path is processed. An unknown tag or branch key requires every possible branch and fallback/no-match path to compile and produce compatible output counts and schemas, including reference schemas.
- A fallback may be needed to produce outputs even when the listed keys cover the intended runtime tag range; the no-match path is not inferred as impossible.
equal
(other -- cond) Compares variants with matching alternative-list schemas and active payloads.- Prototype values do not matter. A schema mismatch is a compile-time error,
Variants' supported types differ. - A non-iterable Dict without
equalfails withBuilt-in text, tuple, Iter, or Iterable expected. - Different active tags return
FALSE. Matching tags compare the active payloads using library=dispatch, including iterable and equal-method adapters; the builtin=coversCondand numeric Variant payloads; directTextalternatives are unsupported. - Payload equality must be supported for every alternative whose comparison is processed. Unknown tags can require comparison support for alternatives that are not active at run time.
Assign, switch tag, and compare
"String" use
"Variant" use
"control" use
{} Int32 {} [
v0: (Int32 Nat8) Variant;
v1: (Int32 Nat8) Variant;
("tag0=" v0.getTag LF) printList
7n8 1 @v0.assign
7n8 1 @v1.assign
("tag1=" v0.getTag LF
"value1=" 1 @v0.get LF
"equal0=" @v1 @v0.equal LF) printList
123 0 @v1.assign
("tag2=" v1.getTag LF
"value2=" 0 @v1.get LF
"equal1=" @v1 @v0.equal LF) printList
0
] "main" exportFunction
Expected Output
tag0=0
tag1=1
value1=7
equal0=TRUE
tag2=0
value2=123
equal1=FALSE
visit branch dispatch
"String" use
"Variant" use
"control" use
{} Int32 {} [
v: (Int32 Nat8) Variant;
7n8 1 @v.assign
(0 [x:; ("int=" x LF) printList]
1 [x:; ("nat=" x LF) printList]
[("default" LF) printList]) @v.visit
0
] "main" exportFunction
Expected Output
nat=7
Lifetime and whole-object transfer
- Copying an immutable Variant copies its active alternative using that alternative's copy behavior.
- Moving a mutable Variant transfers the active value and reinitializes the source at tag 0. Whole-object assignment follows the same transfer rules.
- Contained reference aliases follow the alternative's own semantics; this is not a generic deep copy of referenced objects.
Access and reference stability
getandgetUncheckedreturn borrowed views into the object's payload storage. The result is mutable only when both the receiver view and the selected prototype view permit mutation; otherwise it is immutable. Use mutable prototype views when writable alternatives are required.- A matching
visitbranch receives the same view thatgetwould return for its key. Copying the referenced value requires an explicit copy operation and the alternative's copy support. setTag,assign, whole-object assignment, and normal destruction may destroy or replace the active branch and invalidate earlier returned views.
Module helper
- When usable, the result accounts for the active alternative only.
Known issue: an active scalar or String payload fails compilation with The only predicate named «getHeapUsedSize» did not match. Importing memory does not repair the Variant overload. This helper requires a visible getHeapUsedSize overload for every alternative whose branch is processed; an unknown tag can require all alternatives; do not rely on this entry for heap accounting of scalar or String values.