Structs are tuples as it was mentioned in [types] article. Structs can contain items of different types.

Struct constant

Structs can be defined in two ways. The first way assumes using property names. Nested structs should be taken into parenthesis.

const s1 := {name: "John Doe", birthday: {year: 1986, month: 6, day: 24}};

The second way assumes specifying only values without their names. In this case property names will be assigned implicitly and will be _1, _2 and so on.

const s2 := {"John Doe", {1986, 6, 24}};

Mixing this two ways is not permitted, struct should has all properties with names or it should has no names at all. Struct properties can be accessed like list items directly after definition. {name: "John Doe", birthday: {year: 1986, month: 6, day: 24}}.name will result "John Doe".

As it was told earlier, struct types are compatible if their properties is compatible. Thats why next example is valid:

var user: struct(name: string, age: int) := {"John", 26};
var book: struct(title: string, price: float) := {"Perfect Code", 46.21};
book := user;        # this assign is correct cause user and book are 
                     # compatible
io::put(book.title); # "John" will be printed

Struct decomposition

As it was noticed above, struct constant is actually just a tuple of values. During assignment these values are assigned to struct properties.

var user: struct(name: string, age: int) := {"John", 26};

But it is also possible to decompose existing struct into separate values.

var name: string;
var age: int;
{name, age} := user;

If function returns more than one result, all returned values can be assigned to properties of struct with compatible type.