# Methods as Functions

### Methods as Functions

Zig has no class syntax.

A function that belongs with a type is written inside the type.

```zig
const Point = struct {
    x: i32,
    y: i32,

    pub fn moveRight(p: *Point, n: i32) void {
        p.x += n;
    }
};
```

The struct has two fields and one function. The function is part of the namespace of `Point`.

It is called with the type name:

```zig
Point.moveRight(&point, 5);
```

A complete program:

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

const Point = struct {
    x: i32,
    y: i32,

    pub fn moveRight(p: *Point, n: i32) void {
        p.x += n;
    }
};

pub fn main() void {
    var point = Point{
        .x = 10,
        .y = 20,
    };

    Point.moveRight(&point, 5);

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

The output is:

```text
x = 15, y = 20
```

There is no hidden receiver. The first parameter is ordinary. It has the type `*Point`, a pointer to `Point`.

Zig also lets this call be written with dot syntax:

```zig
point.moveRight(5);
```

This is the same call. Zig passes `&point` as the first argument because `moveRight` expects `*Point`.

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

const Point = struct {
    x: i32,
    y: i32,

    pub fn moveRight(p: *Point, n: i32) void {
        p.x += n;
    }
};

pub fn main() void {
    var point = Point{
        .x = 10,
        .y = 20,
    };

    point.moveRight(5);

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

The output is still:

```text
x = 15, y = 20
```

This is method-call syntax, but the method is still just a function.

A function may take the value by copy.

```zig
const Point = struct {
    x: i32,
    y: i32,

    pub fn sum(p: Point) i32 {
        return p.x + p.y;
    }
};
```

Call it with:

```zig
const n = point.sum();
```

The value `point` is passed as the first argument.

A complete program:

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

const Point = struct {
    x: i32,
    y: i32,

    pub fn sum(p: Point) i32 {
        return p.x + p.y;
    }
};

pub fn main() void {
    const point = Point{
        .x = 7,
        .y = 8,
    };

    const n = point.sum();

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

The output is:

```text
15
```

Use a value parameter when the function only needs to read the value and the value is small.

Use a pointer parameter when the function must change the value.

```zig
pub fn reset(c: *Counter) void {
    c.value = 0;
}
```

Use a pointer to constant when the function reads a large value without copying it.

```zig
pub fn area(r: *const Rectangle) u32 {
    return r.width * r.height;
}
```

This says that the function receives an address, but it will not modify the rectangle through that address.

```zig
const Rectangle = struct {
    width: u32,
    height: u32,

    pub fn area(r: *const Rectangle) u32 {
        return r.width * r.height;
    }
};
```

Call it in the same way:

```zig
const a = rect.area();
```

Zig chooses the correct first argument form from the function parameter type.

If the first parameter is `Rectangle`, the value is passed.

If the first parameter is `*Rectangle`, a pointer is passed.

If the first parameter is `*const Rectangle`, a pointer to constant is passed.

This makes the call site short while keeping the function signature explicit.

A common style is to name the first parameter `self`.

```zig
const Counter = struct {
    value: u32,

    pub fn inc(self: *Counter) void {
        self.value += 1;
    }

    pub fn get(self: Counter) u32 {
        return self.value;
    }
};
```

`self` is only a parameter name. It has no special meaning in the language.

A complete counter:

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

const Counter = struct {
    value: u32,

    pub fn inc(self: *Counter) void {
        self.value += 1;
    }

    pub fn add(self: *Counter, n: u32) void {
        self.value += n;
    }

    pub fn get(self: Counter) u32 {
        return self.value;
    }
};

pub fn main() void {
    var counter = Counter{
        .value = 0,
    };

    counter.inc();
    counter.add(4);

    std.debug.print("{d}\n", .{counter.get()});
}
```

The output is:

```text
5
```

The functions are ordinary declarations. They may be called either way:

```zig
counter.inc();
Counter.inc(&counter);
```

Both mean the same thing.

Functions inside structs may also be constructors.

```zig
const Point = struct {
    x: i32,
    y: i32,

    pub fn init(x: i32, y: i32) Point {
        return Point{
            .x = x,
            .y = y,
        };
    }
};
```

Call it with the type name:

```zig
const p = Point.init(10, 20);
```

`init` is only a name. Zig does not treat it specially. It is a convention.

A type may have several constructor-like functions.

```zig
const Point = struct {
    x: i32,
    y: i32,

    pub fn init(x: i32, y: i32) Point {
        return .{
            .x = x,
            .y = y,
        };
    }

    pub fn zero() Point {
        return .{
            .x = 0,
            .y = 0,
        };
    }
};
```

Inside a function that returns `Point`, the literal may use `.{ ... }` because the return type is known.

```zig
return .{
    .x = 0,
    .y = 0,
};
```

This is the same as writing:

```zig
return Point{
    .x = 0,
    .y = 0,
};
```

Methods are useful because they keep operations near the data they operate on. They do not add inheritance, virtual dispatch, or hidden fields. They are namespaced functions with a convenient call form.

Exercises.

7-9. Add a method `moveUp` to `Point` that adds to `y`.

7-10. Define a `Rectangle` struct with `width` and `height`. Add an `area` method.

7-11. Define a `Counter` struct with `inc`, `dec`, and `reset` methods.

7-12. Write a constructor function `Point.init(x, y)` and use it in `main`.

