In other words, the "problem" is that in order for you to be able to stuff a
bunch of items into a "bag", shake the bag, and then pull one out of it - and
**still knowing the type of what you pulled out** \- requires storing type
information together with each item. Nim, as many statically typed compiled
languages, don't do that generally, since variables are typed and thus the
compiler has ensured that a given variable will never hold something of a
different type.
And if you use an object variant, then you are basically wrapping your items
and adding a type field (the discriminating field). AFAICT with some
experimental code, object variants use C unions also, that's neat. This all got
me curious so I slapped together the code below, note the **packed** pragma
which is needed or you will not understand the sizeofs
type
# We create an enum so we can choose which variant of Foo we are creating.
# Nim will use a single byte to represent these two values.
NodeKind = enum nkInt, nkFloat
# The Foo type is an object (not a ref to an object, but the object
itself)
# which has a kind field (1 byte) showing which variant this is.
# Then we have two different fields but Nim knows a given Foo will only
# ever use one of the fields, so it will compile this to a C union, which
mea$
# the two fields will use the same memory location.
Foo = object {.packed.} # We need packed here to make sure memory
is n$
case kind: NodeKind # This field is the discriminator, 1 byte
of nkInt: intVal: int # Typically 8 bytes
of nkFloat: floatVal: float # Typically 8 bytes, but same location as
intV$
# An array of Foos. Note that these are not refs to Foo, but *actual* Foos.
# The array is of static length so the memory occupied here will be:
# 1 byte - Kind of first Foo
# 8 byte - Either an int or float
# 1 byte - Kind of second Foo
# 8 byte - Either an int or float
# NOTE: This is for a 64 bit machine typically.
var x = [Foo(kind: nkInt, intVal: 12), Foo(kind: nkFloat, floatVal: 3.4)]
echo "Size of single Foo: " & $sizeof(x[0]) # Should print 9
echo "Size of array: " & $sizeof(x) # Should print 18
echo "Size of kind: " & $sizeof(x[0].kind) # Should print 1
echo "Size of a single int: " & $sizeof(x[0].intVal) # Should print 8
echo "Size of a single float: " & $sizeof(x[0].floatVal) # Same here.
echo x[0]
echo x[1]
# Or a seq which can dynamically grow but uses the same storage in the
# backing memory as far as I know.
var s = @[Foo(kind: nkInt, intVal: 12), Foo(kind: nkFloat, floatVal: 3.4)]
echo s[0]
s.add(Foo(kind: nkFloat, floatVal: 99.3))
echo s