2.5.2.1.5 Variant Values
A Variant value is a VBVariantValue. A value let-coerced to Variant is wrapped in a VBVariantValue; see RD-VBAL §5.5.1.2 Runtime semantics (MS-VBAL §5.5.1.2.12 Let-coercion to Variant).
A VBVariantValue wraps the whole value, which need not be a scalar. A Variant may wrap another Variant.
Type Information
A VBVariantValue's own TypeInfo mirrors the TypeInfo of its wrapped value. Ordinary destination-type dispatch, in let-coercion and in operator and effective-type determination, therefore picks the same strategy it would for the unwrapped value.
The C# instance of a Variant value stays a VBVariantValue. It is not an instance of the wrapped value's concrete type.
👉 Because a
VBVariantValue'sTypeInfomirrors its wrapped value's, a direct cast or pattern-match on an operand downstream breaks as soon as the operand is a non-defaultVariant: the instance is still theVBVariantValue, not the wrapped value.Any code that short-circuits on a
TypeInfomatch, or pattern-matches aVBTypedValueoperand against a concrete value type directly, must unwrap aVBVariantValuefirst. The unwrap is recursive, because aVariantmay wrap anotherVariant. See RD-VBAL §5.5.1.2 Runtime semantics.
VBVariantValue computes its VarType on construction: its VBVarType tag, the COM VARENUM-compatible tag, via the VBType-to-VBVarType mapping. See RD-VBAL §6.1.1 Predefined Enums (VbVarType).
Storage
VBVariantValue.Value is computed from VBVariantValue.Handle. Handle is the single source of truth for a Variant's value.
Storage holds the wrapped VBTypedValue of a Variant itself inside a VBRuntimeVariantValue box.
| Step | Behaviour |
|---|---|
| Construction | The VBVariantValue constructor binds the new VBVariantValue to its own VBRuntimeVariantValue box (self-binding on construction). |
| Store | SymbolAddressTable.FreshBinding re-boxes the Variant's wrapped value into a fresh VBRuntimeVariantValue on every store. See RD-VBAL §2.3.1.2 Session Services. |
| Read | The VBRuntimeVariantValue box is read back with the wrapped value intact. |
- A
Variant'sVBVarTypetag is carried on itsVBRuntimeVariantValuebox. The tag round-trips through storage alongside the value itself. Variantvalues use the same boxing pattern for storage as arrays (VBArrayType.CreateValue, VBRuntimeArrayValue); see RD-VBAL §2.5.2.1.2 Array Values. Three kinds of value are location-identified this way: an array, aVariant, and a UDT (RD-VBAL §2.5.2.1.3 User-Defined Type (UDT) Values).- 👉 A
Variantvalue round-trips through storage intact. AVariantread back from a variable, array element, or field carries the value that was stored, not a new, unrelatedEmpty. - A
Variant's ownBoxedValueunwraps all the way to the managed value. See RD-VBAL §6.0 Standard Library.
Interop Representation
RD-VBAL specifies an interop representation for the underlying managed value of a VBVariantValue: a managed struct type, for eventual interop with actual COM (unmanaged) variant values.
Note
Not implemented. The interop struct (ValueType / ValueAlloc / ValuePtr) is not declared in the SDK. A VBVariantValue wraps its value through VBRuntimeVariantValue instead; see Storage.
The specified internal representation (struct) has three members:
| Member | Type | Description |
|---|---|---|
ValueType |
VBVariantValueType |
A flag that identifies the variant value type, such as Empty, Integer, Dispatch or BString. |
ValueAlloc |
ScopeKind | Gives the host the allocation scope of the value. |
ValuePtr |
long |
A pointer to the value, in the memory space specified by the ScopeKind (ValueAlloc). |
A VBVariantValue is always allocated in the heap memory, in the same memory space as object values (RD-VBAL §2.5.2.1.4 Object Values).
External addressing of the host process memory makes it possible for a VBVariantValue to wrap an externally-defined object reference; see RD-VBAL §4.0 Program Structure and Organization.
Unwrapping
Unwrapping a VBVariantValue through the interop struct consists of:
- Look up its allocated internal struct.
- Retrieve the struct's
ValuePtr. - Look up the
ValuePtrvalue in the appropriate memory space.
Unwrapping yields a scoped VBTypedValue. The yielded value may or may not be an immediately usable intrinsic data type: it may be another VBVariantValue, which requires a new unwrapping frame.
⏮️ RD-VBAL §2.5.2.1.4 Object Values | ⏭️ RD-VBAL §2.6 Diagnostics