Skip to content
IsaacShelton edited this page Mar 21, 2022 · 2 revisions

Unions

Unions allow for multiple data types to share the same piece of memory

Declaration

Unions are declared by using the union keyword, an identifier, and a field list

union IntOrFloat32 (i int, f float)

Usage Example

import basics

struct CatInfo (furriness int)
struct DogInfo (is_energetic bool)

enum AnimalKind (CAT, DOG)
union AnimalInfo (cat CatInfo, dog DogInfo)

struct Animal (kind AnimalKind, info AnimalInfo)

func main {
   animal Animal
   animal.kind = AnimalKind::DOG
   animal.info.dog.is_energetic = true
   print(animal)

   animal.kind = AnimalKind::CAT
   animal.info.cat.furriness = 10
   print(animal)
}

func toString(animal Animal) String {
    exhaustive switch animal.kind {
    case AnimalKind::CAT, return "Cat, " + toString(animal.info.cat.furriness)
    case AnimalKind::DOG, return "Dog, " + toString(animal.info.dog.is_energetic)
    }
    return "Invalid Animal"
}

Memory Management

The __defer__ and __pass__ management procedures are not automatically generated for union types, since it cannot be known which fields require operations.

import basics

union StringOrInt (s String, i int)

func main {
    soi StringOrInt
    soi.s = "Hello".clone()
    
    // DANGEROUS: soi.s never freed, since StringOrInt.__defer__() doesn't exist
}

Because of this, __defer__ must be manually called on fields when applicable.

import basics

union StringOrInt (s String, i int)

func main {
    soi StringOrInt
    soi.s = "Hello".clone()
    
    // OK: soi.s is always assumed to be valid, and will be freed
    // This is only required since 'String' has a '__defer__' method
    // that is used to clean up
    soi.s.__defer__()
}

When using a different type within a union, the same process applies. Otherwise, dynamic memory references inside the previously used type could be overwritten and then be leaked or incorrectly freed.

import basics

union StringOrInt (s String, i int)

func main {
    soi StringOrInt
    soi.s = "Hello".clone()
    
    // We must clean up the string before using 'soi' as a different type
    soi.s.__defer__()
    
    soi.i = 10
    
    // We don't need to clean up here, since we know that 'soi' is only an 'int',
    // which doesn't need to be freed
}

Anonymous Unions and Anonymous Composite Fields

Unions can be used anonymously just like structures.

struct FloatOrInt (is_float bool, union (f float, i int))

union Vec3d (
    struct (
        x double,
        y double,
        z double
    ),
    raw 3 double
)

func exampleFunction {
    floating_int union (as_float float, as_int int)
    floating_int.as_float = 1.0
    printf("%d\n", floating_int.as_int)
}

See section in structures for more information

Clone this wiki locally