# Structs

> Defining structs, constructing them with positional or keyword fields, reading and changing fields, methods with self and ref self, static methods, printing, equality, and value semantics.

Source: https://docs.brinelang.org/language/structs/

A struct is a named record of fields, with methods defined inside it. Structs are values like everything else in Brine: copying one copies its fields, `==` compares fields, and `print` shows them. A method that changes its struct takes `ref self`.

## Defining and constructing

[Section titled “Defining and constructing”](#defining-and-constructing)

```brine
struct Point:
    x: int
    y: int


struct Line:
    start: Point
    end: Point
    label: str


fn main():
    let a = Point(x=1, y=2)        # keyword: any order
    let b = Point(3, 4)            # positional: declaration order
    var line = Line(label="diagonal", start=a, end=b)
    line.end.y = 40                # nested fields
    print(a.x + b.y)
    print(line)
    print(f"from {line.start} to {line.end}")
    print(a == Point(1, 2), a != b)
```

Output

```text
5
Line(start=Point(x=1, y=2), end=Point(x=3, y=40), label="diagonal")
from Point(x=1, y=2) to Point(x=3, y=40)
true true
```

* Each field has a name and a type. Fields have no default values.
* Construct with all fields positionally, in declaration order (`Point(3, 4)`), or all by keyword, in any order (`Point(y=4, x=3)`). Don’t mix the two.
* Read and assign fields with a dot. Assigning needs a `var`; a `let` struct can’t change at all.

Every field needs a value:

```brine
struct Point:
    x: int
    y: int


fn main():
    let p = Point(x=1)
    print(p)
```

```text
error[E0302]: missing field `y` in `Point(...)`
 --> main.br:6:13
  |
6 |     let p = Point(x=1)
  |             ^^^^^^^^^^ every field needs a value
  = run `brine explain E0302` for more about this error
error: could not compile due to 1 error
```

## Methods

[Section titled “Methods”](#methods)

Methods are functions declared inside the struct. The first parameter decides what a method may do:

* `self`: the method reads its receiver (a read-only copy, like any parameter).
* `ref self`: the method can change its receiver. It can only be called on something you could pass as `ref`: a `var`, or an element or field of one.
* no `self`: a static method, called on the type: `Particle.at_rest(1.0)`. Use these for constructors.

```brine
struct Particle:
    pos: float
    vel: float


    fn energy(self) -> float:                # reads its receiver
        return 0.5 * self.vel * self.vel


    fn step(ref self, dt: float):            # changes its receiver
        self.pos += self.vel * dt


    fn at_rest(pos: float) -> Particle:      # no self: a static method
        return Particle(pos=pos, vel=0.0)


fn main():
    var p = Particle(pos=0.0, vel=2.0)
    p.step(0.5)
    p.step(0.5)
    print(p, p.energy())
    let q = Particle.at_rest(1.0)
    print(q)
    var ps = [Particle(0.0, 1.0), Particle(5.0, -1.0)]
    for i in 0..len(ps):
        ps[i].step(1.0)                      # on an array element
    print(ps)
```

Output

```text
Particle(pos=2.0, vel=2.0) 2.0
Particle(pos=1.0, vel=0.0)
[Particle(pos=1.0, vel=1.0), Particle(pos=4.0, vel=-1.0)]
```

The call `p.step(0.5)` doesn’t need a `ref` at the call site: the method’s name already says what it does, and the compiler checks that `p` can be changed.

```brine
struct Counter:
    n: int


    fn bump(ref self):
        self.n += 1


fn main():
    let c = Counter(n=0)
    c.bump()
```

```text
error[E0401]: cannot call `ref self` method `bump` on `c` because it was declared with `let`
 --> main.br:9:5
  |
9 |     c.bump()
  |     ^ immutable
8 |     let c = Counter(n=0)
  |         - declared here
  |
  = help: declare it with `var c = ...` to make it mutable
  = run `brine explain E0401` for more about this error
error: could not compile due to 1 error
```

In a plain `self` method, `self` is read-only, and assigning to one of its fields is [E0403](/reference/errors/#e0403). `mut self` isn’t allowed: it would only change a copy. To return a changed copy, build a new value: `return Particle(pos=self.pos + 1.0, vel=self.vel)`.

Methods may have type parameters of their own; see [generics](/language/generics/#methods-with-their-own-type-parameters).

## Printing and equality

[Section titled “Printing and equality”](#printing-and-equality)

`print`, `str(...)` and f-strings show a struct as its name and its fields, nested values included: `Point(x=1, y=2)`. Strings inside are quoted (`label="diagonal"`).

`==` and `!=` compare two structs of the same type field by field. Structs can’t be ordered: `<` on two `Point`s is [E0305](/reference/errors/#e0305). A struct whose fields are all valid map keys (integers, `bool`, `str`, enums, and arrays, tuples and structs of those) can be a map key too.

## Value semantics

[Section titled “Value semantics”](#value-semantics)

A struct is a value. `var q = p` copies `p`, and passing a struct to a function passes a copy, so changing one never changes the other. (The copy is cheap: arrays and strings inside are copy-on-write.)

```brine
struct Point:
    x: int
    y: int


fn moved(p: Point, dx: int) -> Point:
    var q = p              # a copy
    q.x += dx
    return q


fn main():
    let a = Point(1, 2)
    let b = moved(a, 10)
    var c = a
    c.y = 0
    print(a, b, c)
```

Output

```text
Point(x=1, y=2) Point(x=11, y=2) Point(x=1, y=0)
```

To let a function change a struct the caller owns, use a `ref self` method or a `ref` parameter (see [functions](/language/functions/#ref-parameters)).

## Recursive structs

[Section titled “Recursive structs”](#recursive-structs)

A struct can’t contain itself directly, because it would have infinite size. Put the recursive part in an array (`children: [Node]`) or use a recursive [enum](/language/enums-and-match/#recursive-enums).

```brine
struct Node:
    value: int
    next: Node


fn main():
    print(1)
```

```text
error[E0309]: struct `Node` contains itself and would have infinite size
 --> main.br:1:1
  |
1 | struct Node:
  | ^^^^^^ recursive struct
  |
  = help: store the recursive part inside an array or an enum, e.g. `children: [Node]`
  = run `brine explain E0309` for more about this error
error: could not compile due to 1 error
```

## Summary

[Section titled “Summary”](#summary)

* `struct Name:` followed by `field: Type` lines and `fn` methods.
* Construct positionally (`Point(1, 2)`) or by keyword (`Point(x=1, y=2)`), not mixed; every field needs a value.
* `self` methods read, `ref self` methods change the receiver (which must be a `var`), methods without `self` are static (`Type.method()`).
* Structs print as `Name(field=value, ...)` and compare with `==` field by field.
* Copies are independent. Generic structs: see [generics](/language/generics/).
