Struct

Structs with Parametric Polymorphism (Parapoly)

Table_Slot :: struct($Key, $Value: typeid) {
    occupied: bool,
    hash:    u32,
    key:     Key,
    value:   Value,
}
slot: Table_Slot(string, int)
  • Example :

    • Odin-handle-map with $HT: typeid :

      • Caio:

        Handle_Map :: struct($T: typeid, $HT: typeid, $N: int) {
            // Each item must have a field `handle` of type `HT`.
            items: [N]T,
            num_items: u32,
            next_unused: u32,
            unused_items: [N]u32,
            num_unused: u32,
        }           
        
        • I don't understand the use of $HT: typeid , the HT  is not used inside this struct, so why is it there? Does it have the same influence from outside the struct?

      • Thag:

        • It's because it allows other procs to then infer the handle type based on the type of the map

        • i.e. remove :: proc(m: ^Handle_Map($T, $HT), h: HT)

        • notice how HT  can be known from the type specified in the handle map definition

      • Caio:

        • so it's just type information for the handle it holds? I mean, if I were to make a distinct  handle?

      • Thag:

        • you're right, it's type info that is then used by other procs at compile time.

      • Chamberlain:

        • I've done something similar with my Vulkan abstraction, haha. Good to see someone else used poly this way too.

Subtype Polymorphism (Keyword using )

  • When using using  on structs , this gives subtyping (inheritance).

  • "It's like embedding  in Go, but a little more explicit".

  • Technically it is possible to "force" OOP via the use of "function tables" ("V tables", virtual tables) and using using  to simulate inheritance:

  • Using using  in other places:

    • In procedures :

      • Ginger Bill: "It was a mistake".

      • Teej: "I can see this being useful when using RayLib a lot inside a function and I just want to drop the rl. ".

      • Ginger Bill: "I still think that's bad, don't use it. It's just 3 characters, it's not worth it".

      • Ginger Bill: "I regret adding this as a feature, because it only leads to unreadable spaghetti code. Try not to use it, this is a mistake.".

    • In file scopes :

      • Not possible.

      • Ginger Bill: "I disallowed using using  at the file scope, because it makes it harder to understand where the code is coming from".

Struct Memory Layout

#packed
  • Removes padding between fields that is normally inserted to ensure all fields meet their type’s alignment requirements.

  • The fields remain in source order.

  • Useful where the structure is unlikely to be correctly aligned (the insertion rules assume it is ), or if space savings are more important than access speed.

  • Accessing a field in a packed struct may require copying the field out into a temporary location, or using a machine instruction that doesn’t assume the pointer is correctly aligned, to be performant or avoid crashes on some systems. (See intrinsics.unaligned_load .)

struct #packed {...} 
#aligned(N)
  • Specifies that the struct will be aligned to N  bytes.

  • This applies to the struct itself, not its fields.

  • Fields remain in source order.

  • Can also be applied to a union .

struct #align(4) {...} 
#raw_union
  • Struct’s fields will share the same memory space, similar to union s in C.

  • All fields share the same offset ( 0 ).

  • Useful especially for bindings.

struct #raw_union {...} 
Equivalence
  • Arrays :

    Vec3 :: [3]f32 
    Vec3 :: struct { 
        x: f32, 
        y: f32, 
        z: f32,
    }
    
  • Matrices

    Matrix4x4 :: #row_major matrix[4, 4]f32
    Matrix4x4 :: struct {
        m11, m12, m13, m14: f32,
        m21, m22, m23, m24: f32,
        m31, m32, m33, m34: f32,
        m41, m42, m43, m44: f32,
    }
    

Reflect

Struct
Struct Fields

Other tags

#no_copy
  • This tag can be applied to a struct  to forbid copies. The initialization of a #no_copy  type must be implicitly zero, a constant literal, or a return value from a call expression.

Mutex :: struct #no_copy {
    state: uintptr,
}

main :: proc() {
    m: Mutex
    v1 := m  // This line will raise an error.
    p  := &m
    v2 := p^ // So will this line.
}