# Generic Functions

### Generic Functions

A function in Zig can take types as parameters.

This is the basis of generic programming in the language. Instead of writing separate functions for integers, floating-point values, or user-defined types, a single function can operate on many kinds of values.

Here is a simple example:

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

fn add(comptime T: type, a: T, b: T) T {
    return a + b;
}

pub fn main() void {
    const x = add(i32, 3, 4);
    const y = add(f64, 1.5, 2.25);

    std.debug.print("{d}\n", .{x});
    std.debug.print("{d}\n", .{y});
}
```

The output is:

```text
7
3.75
```

The first parameter is unusual:

```zig
comptime T: type
```

`T` is not a normal runtime value. It is known at compile time.

The type of `T` is:

```zig
type
```

In Zig, types themselves are values available during compilation.

The call:

```zig
add(i32, 3, 4)
```

passes the integer type `i32` into the function.

Inside the function, the parameters become:

```zig
a: i32
b: i32
```

and the return type becomes:

```zig
i32
```

The compiler generates a specialized version of the function for that type.

The second call:

```zig
add(f64, 1.5, 2.25)
```

creates another specialization using `f64`.

The function body is written once:

```zig
return a + b;
```

but the generated machine code depends on the concrete type.

A generic function may also infer types from arguments.

This version does not require the caller to pass `T` explicitly:

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

fn max(a: anytype, b: anytype) @TypeOf(a, b) {
    return if (a > b) a else b;
}

pub fn main() void {
    const x = max(10, 20);
    const y = max(3.5, 1.25);

    std.debug.print("{d}\n", .{x});
    std.debug.print("{d}\n", .{y});
}
```

The output is:

```text
20
3.5
```

`anytype` means the compiler should infer the parameter type from the argument.

The return type is:

```zig
@TypeOf(a, b)
```

This builtin asks the compiler to compute a common type from the arguments.

Generic functions are compiled lazily. Zig does not generate machine code for every possible type. A specialization appears only when the function is used.

This program is legal:

```zig
fn square(comptime T: type, x: T) T {
    return x * x;
}

pub fn main() void {}
```

Even if `square` contains invalid operations for some types, no error occurs until the function is instantiated with such a type.

For example:

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

fn square(comptime T: type, x: T) T {
    return x * x;
}

pub fn main() void {
    const s = square([]const u8, "zig");
    _ = s;
}
```

fails because slices cannot be multiplied.

The compiler reports the error only after the function is used with that type.

Generic programming in Zig is based on ordinary language features:

- compile-time execution
- types as values
- normal function calls
- specialization during compilation

There is no separate template language.

Exercise 11-1. Write a generic `min` function.

Exercise 11-2. Write a generic `swap` function using pointers.

Exercise 11-3. Write a generic function that returns the larger of three values.

Exercise 11-4. Modify `add` so it works only for integer types.

