Post

Using Structures

Structures are a way to group related data together in Glu. They are similar to classes in other languages but are typically used for simpler data structures. In this section, we will cover how to declare and use structures in Glu.

Declaring a Structure

A structure in Glu is declared using the struct keyword followed by the structure’s name and its fields. Each field has a name and a type. Here are some examples of structure declarations:

1
2
3
4
struct Person {
    name: String,
    age: Int,
}

In this example, the structure Person has two fields: name of type String and age of type Int. You can also provide default values for the fields:

1
2
3
4
struct Person {
    name: String = "Unknown",
    age: Int = 0,
}

In this example, the fields name and age are initialized to Unknown and 0 respectively.

The last comma in the field list is optional, so you can write the following:

1
2
3
4
struct Person {
    name: String,
    age: Int
}

Declaring an Instance of a Structure

You can declare a variable that contains a structure and initialize it with or without default values.

1
2
3
4
5
6
7
8
9
10
struct Person {
    name: String = "Unknown",
    age: Int = 0
}

func main() {
    let person1: Person = {}; //  initialisation with default values
    let person2: Person = { "Alice", 25 }; // initialisation with custom values
    let person3: Person = { "Bob" }; // initialisation with custom name but with default age
}

Accessing Fields of a Structure

You can access the fields of a structure using the dot operator (.). For example:

1
2
3
4
5
6
7
8
9
10
struct Person {
    name: String,
    age: Int
}

func main() {
    let person: Person = { "Alice", 25 };
    std::print(person.name); // prints "Alice"
    std::print(person.age); // prints 25
}

Packed Structures

Glu allows you to pack structures for memory efficiency using the @packed attribute. This feature exists in other programming languages and can be useful for certain applications where memory usage is critical.

1
2
3
4
@packed struct Data {
    a: Int8,
    b: Int64,
}

In this example, the structure Data is packed, meaning its fields are laid out in memory without padding. Let’s compare the memory layout before and after using the @packed attribute.

Without @packed attribute:

1
2
3
4
struct Data {
    a: Int8,
    b: Int64,
}

Without the @packed attribute, the compiler may add padding between the fields to align them in memory, improving access speed but using more memory. For example, an Int8 field followed by an Int64 field might look like this in memory:

Name Size (bytes)
a 1
padding 7
b 8

This layout ensures that b is aligned to an 8-byte boundary, but it uses a total of 16 bytes (1 + 7 + 8).

With @packed attribute:

1
2
3
4
@packed struct Data {
    a: Int8,
    b: Int64,
}

When the @packed attribute is used, no padding is added, and the fields are laid out consecutively in memory:

Name Size (bytes)
a 1
b 8

This layout uses only 9 bytes (1 + 8), saving memory. However, accessing b may be slower because it is not aligned to an 8-byte boundary.

Using the @packed attribute allows you to gain memory efficiency at the cost of execution speed. This trade-off should be considered when deciding whether to pack a structure.

Overloading Operators for Structures

Glu supports operator overloading, allowing you to define custom behavior for operators when used with your structures. Here is an example of overriding the equality operator == for the Person structure:

1
2
3
operator ==(a: Person, b: Person) -> Bool {
    return a.name == b.name && a.age == b.age;
}

In this example, the == operator is overridden to compare the fields name and age of two Person structures.

Example Program with Structures

Here is a complete example program that demonstrates the use of structures in Glu:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
// Declare a structure with default values
struct Person {
    name: String = "Unknown",
    age: Int = 0
}

// Override the equality operator for the Person structure
operator ==(a: Person, b: Person) -> Bool {
    return a.name == b.name && a.age == b.age;
}

func main() {
    let person1: Person = {}; // initialisation with default values
    let person2: Person = { "Bob", 30 };

    std::print(person1.name); // prints "Unknown"
    std::print(person2.age); // prints 30

    if person1 == person2 {
        std::print("The two persons are the same.");
    } else {
        std::print("The two persons are different.");
    }
}

In this example, we declare a structure Person with default values, override the == operator for the Person structure, and use the structure in the main function to create two instances of Person and compare them.

By using structures, you can organize your data more effectively and make your Glu programs more readable and maintainable.

This post is licensed under CC BY 4.0 by the author.