Oh, my terminology might be off then! Okay, I’ll try to go a bit more into detail. First, let’s see what your example code actually does. To make things more obvious, I will add another field to the Outer
struct.
package experiment
Inner :: struct {
a: int,
}
Outer :: struct {
using inner: Inner,
b: int,
}
doStuff :: proc() {
inners: [dynamic]Inner
// This actually does not append the Outers to the array, but only copies
// the 'inner' fields of the Outers into the array.
// The 'b' fields will be completely gone this way.
a := [2]Inner{Outer{}, Outer{}}
append_elems(&inners, ..a[:])
// ERROR: I cannot append an array of 'Outers'
b := [2]Outer{Outer{}, Outer{}}
append_elems(&inners, ..b[:]) // Cannot assign value 'outers[:]' of type '[]Outer' to '[]Inner' in a procedure argument
}
An array cannot hold values of different types. What is possible though is to store pointers to things of different types. This is actually also how for example C# does it since basically everything in C# is always a pointer anyway.
package experiment
import "core:fmt"
Inner :: struct {
a: int,
}
Outer :: struct {
using inner: Inner,
b: int,
}
main :: proc() {
inners: [dynamic]^Inner
a := [2]Inner{Inner{a=1}, Inner{a=2}}
for &inner in a do append_elem(&inners, &inner)
b := [2]Outer{Outer{a=3, b=5}, Outer{a=4, b=6}}
for &outer in b do append_elem(&inners, &outer)
fmt.printfln("0: %v", inners[0])
fmt.printfln("1: %v", inners[1])
fmt.printfln("2: %v", cast(^Outer)inners[2])
fmt.printfln("3: %v", cast(^Outer)inners[3])
}
Note that for the cast to work, the ‘inner’ field must be the first element of the Outer
struct. The pointer we stored points to the inner field and if it’s the first field, then the address of the whole Outer is the same.