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
    

Reply via email to