# `anytype`

### `anytype`

`anytype` means the function parameter can accept many different types.

It is Zig’s simplest way to write a generic function.

Here is a normal function:

```zig
fn double(x: i32) i32 {
    return x * 2;
}
```

This works only with `i32`.

```zig
const a = double(10);
```

But this does not work:

```zig
const b = double(1.5); // error
```

The function expects an `i32`, not a floating-point number.

With `anytype`, the function can accept different types:

```zig
fn double(x: anytype) @TypeOf(x) {
    return x * 2;
}
```

Now `x` can be an integer, a float, or any other type that supports `* 2`.

```zig
const a = double(@as(i32, 10));
const b = double(@as(f64, 1.5));
```

The return type is:

```zig
@TypeOf(x)
```

That means the function returns the same type as `x`.

#### `anytype` Is Checked at Compile Time

`anytype` does not mean “ignore types.”

It does not make Zig dynamically typed.

Zig still checks everything at compile time.

This function accepts any type, but the body must make sense for the actual type passed in.

```zig
fn double(x: anytype) @TypeOf(x) {
    return x * 2;
}
```

This works:

```zig
const n = double(@as(i32, 21));
```

This does not:

```zig
const s = double("hello"); // error
```

A string cannot be multiplied by `2`.

So `anytype` means:

```text
Let the caller choose the type, then compile a version of this function for that type.
```

It does not mean:

```text
Accept anything at runtime and hope it works.
```

#### A Simple Generic Function

Here is a generic `max` function:

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

The first parameter can be any type.

```zig
a: anytype
```

The second parameter must have the same type as the first:

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

The return type is also the same:

```zig
@TypeOf(a)
```

Now the function works with different numeric types:

```zig
const x = max(@as(i32, 10), @as(i32, 20));
const y = max(@as(f64, 1.5), @as(f64, 0.5));
```

But this should not work:

```zig
const z = max(@as(i32, 10), @as(u32, 20)); // error
```

The second argument must match the first argument’s type.

#### `anytype` Creates a Compile-Time Parameter

A parameter written as `anytype` is known at compile time.

This is why you can inspect its type:

```zig
fn printType(x: anytype) void {
    _ = x;
    @compileLog(@TypeOf(x));
}
```

If you call:

```zig
printType(@as(i32, 123));
printType(@as(bool, true));
```

Zig sees two different calls with two different concrete types.

Conceptually, the compiler treats them like separate versions:

```text
printType for i32
printType for bool
```

This is why `anytype` is powerful. It lets you write one function body, while the compiler still works with real concrete types.

#### `anytype` and Duck Typing

`anytype` is sometimes described as compile-time duck typing.

That means the function does not name an interface. It simply uses operations, and the type must support those operations.

Example:

```zig
fn lengthOf(x: anytype) usize {
    return x.len;
}
```

This works for values that have a `.len` field:

```zig
const a = [_]u8{ 1, 2, 3 };
const n = lengthOf(a);
```

It also works for slices:

```zig
const s: []const u8 = "hello";
const m = lengthOf(s);
```

But it does not work for an integer:

```zig
const bad = lengthOf(@as(i32, 10)); // error
```

An `i32` does not have a `.len` field.

The function accepts any type that has what the function uses.

That is the “duck typing” idea, but it happens at compile time.

#### Better Error Messages with Compile-Time Checks

A plain `anytype` function can produce confusing errors if the wrong type is passed.

For example:

```zig
fn lengthOf(x: anytype) usize {
    return x.len;
}
```

Calling it with an integer gives an error somewhere inside the function body.

You can make the error clearer with a compile-time check:

```zig
fn lengthOf(x: anytype) usize {
    const T = @TypeOf(x);
    const info = @typeInfo(T);

    switch (info) {
        .array => return x.len,
        .pointer => |ptr| {
            if (ptr.size == .slice) {
                return x.len;
            }

            @compileError("lengthOf expects an array or slice");
        },
        else => @compileError("lengthOf expects an array or slice"),
    }
}
```

This is more advanced, but the idea is simple:

```text
Use @typeInfo to inspect the type.
Reject bad types with @compileError.
```

The caller gets a clearer message.

#### `anytype` vs `comptime T: type`

There are two common ways to write generic functions in Zig.

The first uses `anytype`:

```zig
fn identity(x: anytype) @TypeOf(x) {
    return x;
}
```

The second passes the type explicitly:

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

You call them differently.

With `anytype`:

```zig
const a = identity(@as(i32, 10));
```

With explicit type parameter:

```zig
const b = identity(i32, 10);
```

Both are generic.

Use `anytype` when the type can be inferred from the value.

Use `comptime T: type` when the caller should provide the type directly, or when the function needs the type before receiving a value.

#### Example: Generic Swap

Here is a generic swap function:

```zig
fn swap(a: anytype, b: @TypeOf(a)) struct { @TypeOf(a), @TypeOf(a) } {
    return .{ b, a };
}
```

This returns an anonymous tuple-like struct containing the values in reverse order.

```zig
const result = swap(@as(i32, 1), @as(i32, 2));
```

A clearer version uses an explicit type parameter:

```zig
fn swap(comptime T: type, a: T, b: T) struct { T, T } {
    return .{ b, a };
}
```

Call it like this:

```zig
const result = swap(i32, 1, 2);
```

For beginners, the explicit type version is often easier to read.

`anytype` is short and convenient, but explicit `comptime T: type` makes the generic type visible.

#### Example: Printing Any Value

The standard formatting system already supports generic printing, but a simple wrapper shows how `anytype` feels:

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

fn debugPrint(value: anytype) void {
    std.debug.print("{any}\n", .{value});
}

pub fn main() void {
    debugPrint(@as(i32, 123));
    debugPrint(true);
    debugPrint("hello");
}
```

The same function accepts several different types.

The compiler checks each call separately.

#### `anytype` Is Not for Storing Values

`anytype` is used in function parameters.

You cannot use it as a normal variable type:

```zig
var x: anytype = 10; // error
```

This is not what `anytype` means.

A variable must have a specific type.

```zig
var x: i32 = 10;
```

or let Zig infer the specific type:

```zig
var y = @as(i32, 10);
```

`anytype` belongs in function parameter lists:

```zig
fn f(x: anytype) void {
    _ = x;
}
```

#### Avoid Overusing `anytype`

`anytype` is convenient, but it can make APIs harder to understand.

This function is clear:

```zig
fn parsePort(text: []const u8) !u16 {
    // parse text
}
```

This version is less clear:

```zig
fn parsePort(text: anytype) !u16 {
    // what types are allowed?
}
```

If the function really expects a byte slice, say so.

Use `anytype` when the function genuinely works across multiple types.

Do not use it just to avoid thinking about the correct type.

#### A Practical Rule

Use a concrete type when the function expects one kind of value.

```zig
fn countBytes(data: []const u8) usize {
    return data.len;
}
```

Use `anytype` when the function accepts a family of types and the operations are the same.

```zig
fn isEmpty(x: anytype) bool {
    return x.len == 0;
}
```

Use `comptime T: type` when the type itself is an important input.

```zig
fn makeZero(comptime T: type) T {
    return @as(T, 0);
}
```

#### The Main Idea

`anytype` is Zig’s compact syntax for generic function parameters.

```zig
fn f(x: anytype) void {
    _ = x;
}
```

It means the caller can pass different concrete types, and the compiler checks each call at compile time.

It does not remove type checking.

It does not make Zig dynamic.

It simply lets a function be written once and specialized for the actual types used by the caller.

