# Generic Structs

### Generic Structs

A generic struct is a function that returns a type.

This is one of the most important ideas in Zig. Types are values known at compile time, so a function can construct and return new types.

Here is a small stack implementation:

```zig
const std = @import("std");

fn Stack(comptime T: type) type {
    return struct {
        const Self = @This();

        items: []T,
        len: usize,

        pub fn push(self: *Self, value: T) void {
            self.items[self.len] = value;
            self.len += 1;
        }

        pub fn pop(self: *Self) T {
            self.len -= 1;
            return self.items[self.len];
        }
    };
}

pub fn main() void {
    var buffer: [8]i32 = undefined;

    var stack = Stack(i32){
        .items = buffer[0..],
        .len = 0,
    };

    stack.push(10);
    stack.push(20);

    std.debug.print("{d}\n", .{stack.pop()});
    std.debug.print("{d}\n", .{stack.pop()});
}
```

The output is:

```text
20
10
```

The declaration:

```zig
fn Stack(comptime T: type) type
```

means:

- `Stack` is a function
- the parameter is a compile-time type
- the result is another type

The returned value is a struct declaration:

```zig
return struct {
    ...
};
```

Each call creates a distinct type.

For example:

```zig
Stack(i32)
```

and:

```zig
Stack(f64)
```

are different types.

The compiler specializes the struct using the provided type parameter.

Inside the struct, `T` behaves like an ordinary type name:

```zig
items: []T
```

If `T` is `i32`, this becomes:

```zig
items: []i32
```

The declaration:

```zig
const Self = @This();
```

captures the current struct type.

This allows methods to refer to the complete instantiated type:

```zig
pub fn push(self: *Self, value: T) void
```

Without `@This()`, the method would not know the exact struct type.

A generic struct may contain compile-time logic.

This example selects storage size from a parameter:

```zig
fn Buffer(comptime T: type, comptime N: usize) type {
    return struct {
        data: [N]T,
    };
}
```

Usage:

```zig
const IntBuffer = Buffer(i32, 16);
const FloatBuffer = Buffer(f64, 32);
```

The compiler generates different layouts:

```zig
[N]T
```

depends entirely on the compile-time arguments.

Generic structs are commonly used for:

- containers
- allocators
- iterators
- parsers
- memory pools
- protocol implementations

Much of the Zig standard library uses this pattern.

For example, many data structures in `std` are generic over:

- element type
- allocator type
- hashing strategy
- context objects

A generic struct can also expose declarations conditionally.

```zig
fn Pair(comptime T: type) type {
    return struct {
        left: T,
        right: T,

        pub fn swap(self: *@This()) void {
            const temp = self.left;
            self.left = self.right;
            self.right = temp;
        }
    };
}
```

Instantiation:

```zig
var p = Pair(i32){
    .left = 1,
    .right = 2,
};
```

The generated type behaves like any other struct.

There is no runtime penalty for generic code. The compiler resolves the structure and layout during compilation.

A generic struct is therefore not a container holding arbitrary values at runtime. It is a factory for producing concrete types before the program runs.

Exercise 11-5. Write a generic `Point` struct with fields `x` and `y`.

Exercise 11-6. Add a `clear` method to `Stack`.

Exercise 11-7. Write a generic fixed-size queue.

Exercise 11-8. Write a generic struct that stores a value and counts how many times it has been updated.

