# Functions

> Defining functions, parameter and return types, ref and mut parameters, local references, why references never dangle, what main may return, and the evaluation-order rule.

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

Functions are declared with `fn`, with a type on every parameter and the return type after `->`. Arguments are passed by value; a function changes the caller’s variable only through a `ref` parameter, and the caller writes `ref` too, so every change is visible at the call site.

## Defining and calling functions

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

```brine
fn area(w: float, h: float) -> float:
    return w * h


fn greet(name: str):
    print(f"hello, {name}")


fn divmod(a: int, b: int) -> (int, int):
    return (a / b, a % b)


fn main():
    print(area(2.0, 3.0))
    print(area(w=2.0, h=3.0))
    greet("ann")
    let (q, r) = divmod(17, 5)
    print(q, r)
    print(is_even(10))


fn is_even(n: int) -> bool:      # order doesn't matter; recursion is fine
    if n == 0:
        return true
    return not is_even(n - 1)
```

Output

```text
6.0
6.0
hello, ann
3 2
true
```

* Parameter types are required. Local variable types are inferred.
* A function without `-> T` returns nothing (its type is `()`); `return` on its own leaves it early.
* Return several values as a tuple and unpack them at the call.
* Arguments can be named, in the parameters’ order: `area(w=2.0, h=3.0)`. There are no default values.
* Functions can be declared in any order, and may call each other recursively. They are declared at the top level of a module (or as methods); there are no nested functions.

A function with a return type must return on every path:

```brine
fn sign(x: int) -> int:
    if x > 0:
        return 1
    elif x < 0:
        return -1


fn main():
    print(sign(5))
```

```text
error[E0306]: function `sign` may reach the end without returning a value
 --> main.br:1:4
  |
1 | fn sign(x: int) -> int:
  |    ^^^^ expected to return `int`
  |
  = help: add a `return` statement at the end of the function
  = run `brine explain E0306` for more about this error
error: could not compile due to 1 error
```

Functions can be generic (`fn first[T](xs: [T]) -> Option[T]`); see [generics](/language/generics/). They can also carry `requires` and `ensures` contracts that the compiler proves; see [contracts](/proofs/contracts/).

## Parameters are read-only

[Section titled “Parameters are read-only”](#parameters-are-read-only)

A plain parameter is a read-only copy of the argument. Assigning to it is an error that points you at the two alternatives, `mut` and `ref`:

```brine
fn dec(n: int) -> int:
    n -= 1
    return n


fn main():
    print(dec(3))
```

```text
error[E0403]: cannot assign to parameter `n`
 --> main.br:2:5
  |
2 |     n -= 1
  |     ^ parameters are read-only
1 | fn dec(n: int) -> int:
  |        - declared here
  |
  = help: to change a local copy, declare it `mut n: ...`; to change the caller's variable, declare it `ref n: ...` and call with `ref`
  = run `brine explain E0403` for more about this error
error: could not compile due to 1 error
```

## mut parameters

[Section titled “mut parameters”](#mut-parameters)

`mut` makes the parameter a local copy that the function may change. The caller’s value is untouched.

```brine
fn countdown(mut n: int) -> [int]:
    var out: [int] = []
    while n > 0:
        out.push(n)
        n -= 1
    return out


fn main():
    let start = 3
    print(countdown(start), start)
```

Output

```text
[3, 2, 1] 3
```

This works for arrays too, and it’s cheap: the array is copied only when the function first changes it (copy-on-write).

```brine
fn add_all(mut xs: [int], k: int) -> [int]:
    for i in 0..len(xs):
        xs[i] += k
    return xs


fn main():
    let base = [1, 2, 3]
    let more = add_all(base, 10)
    print(base, more)
```

Output

```text
[1, 2, 3] [11, 12, 13]
```

## ref parameters

[Section titled “ref parameters”](#ref-parameters)

A `ref` parameter is the caller’s variable itself: changes to it change the caller’s variable. The caller writes `ref` before the argument, so you can see at the call site which variables a call may change.

```brine
fn fill(ref xs: [int], v: int):
    for i in 0..len(xs):
        xs[i] = v


fn swap(ref a: int, ref b: int):
    let t = a
    a = b
    b = t


fn main():
    var data = [0] * 4
    fill(ref data, 7)
    print(data)
    var x = 1
    var y = 2
    swap(ref x, ref y)
    print(x, y)
    var grid = [[0, 0], [0, 0]]
    fill(ref grid[1], 5)          # an element or a field works too
    print(grid)
```

Output

```text
[7, 7, 7, 7]
2 1
[[0, 0], [5, 5]]
```

The argument must be a `var` (or an element or field of one). Leaving out `ref` at the call is an error:

```brine
fn fill(ref xs: [int], v: int):
    for i in 0..len(xs):
        xs[i] = v


fn main():
    var data = [0] * 3
    fill(data, 7)
```

```text
error[E0402]: parameter `xs` is a `ref`; pass the argument with `ref`
 --> main.br:7:10
  |
7 |     fill(data, 7)
  |          ^^^^ the callee may modify this
  |
  = help: passing by reference is always visible at the call site in brine
  = run `brine explain E0402` for more about this error
error: could not compile due to 1 error
```

Methods that change their receiver take `ref self`; see [structs](/language/structs/#methods).

## Local references

[Section titled “Local references”](#local-references)

`let d = ref data` makes `d` a second name for the variable `data`. Reading or changing `d` reads or changes `data`.

```brine
fn main():
    var data = [1, 2, 3]
    let d = ref data      # `d` is another name for `data`
    d[0] = 100
    d.push(4)
    print(data)
```

Output

```text
[100, 2, 3, 4]
```

The target must be a whole variable (`ref data`, not `ref data[0]`).

## References never dangle

[Section titled “References never dangle”](#references-never-dangle)

References in Brine are *second-class*: you can create them only as parameters and local names, never store them in a struct, an array or a map, and never return them. `ref` isn’t part of any type, so `-> ref int` or a field `r: ref int` doesn’t parse. Storing `d` from above in an array stores a copy of the value.

Because of that, a reference can’t outlive the variable it names, and the compiler always knows which variable each reference points to. There is no lifetime syntax and no borrow checker to satisfy.

### No aliasing between ref arguments

[Section titled “No aliasing between ref arguments”](#no-aliasing-between-ref-arguments)

During a call, a `ref` argument must be the only way to reach that variable. Passing the same variable as `ref` twice (even two different elements of one array) is an error:

```brine
fn swap(ref a: int, ref b: int):
    let t = a
    a = b
    b = t


fn main():
    var xs = [1, 2]
    swap(ref xs[0], ref xs[1])
```

```text
error[E0405]: `xs` is passed as `ref` twice
 --> main.br:8:25
  |
8 |     swap(ref xs[0], ref xs[1])
  |                         ^^^^^ second reference here
  |              ----- passed as `ref` here
  |
  = note: a `ref` argument must be the only access to that variable during the call
  = help: copy the value first: `let xs_copy = ...`
  = run `brine explain E0405` for more about this error
error: could not compile due to 1 error
```

Swap two elements of one array in place instead: `let t = xs[0]`, `xs[0] = xs[1]`, `xs[1] = t`.

Passing the same variable once by `ref` and once by value is fine: the by-value argument is the value from before the call.

## Evaluation order

[Section titled “Evaluation order”](#evaluation-order)

An expression that changes a variable in place (a `ref` argument, a `ref self` method such as `xs.pop()`, `m.remove(k)`) can’t also read that variable somewhere else in the same expression, or change it a second time. The result would then depend on the order the parts are evaluated in, so Brine rules it out and the order never matters.

```brine
fn main():
    var xs = [1, 2, 3]
    print(xs.pop(), xs)
```

```text
error[E0405]: `xs` is changed and also read in the same expression
 --> main.br:3:11
  |
3 |     print(xs.pop(), xs)
  |           ^^^^^^^^ changed here
  |                     -- read here
  |
  = help: make the change in its own statement first, then use the result
  = run `brine explain E0405` for more about this error
error: could not compile due to 1 error
```

Make the change in its own statement first. Reading the variable in the changing call’s own receiver and arguments is fine, because they are evaluated before the call. So are the two sides of `and`/`or`, which run one after the other.

```brine
fn bump(ref x: int) -> int:
    x += 1
    return x


fn main():
    var xs = [1, 2]
    xs.push(len(xs))         # fine: the argument is read before the call
    let last = xs.pop()      # change first...
    print(xs, last)          # ...then read
    var n = 1
    let after = bump(ref n)
    print(after + n)
```

Output

```text
[1, 2] 2
4
```

## main

[Section titled “main”](#main)

`main` takes no parameters (command-line arguments come from `args()`) and returns one of three things:

* nothing: the program exits with code 0;
* an `int`: the exit code;
* a `Result[(), E]`: `Ok(())` exits with 0, and an `Err(e)` prints `error: `and the error to stderr and exits with 1. This lets `main` use the `?` operator.

config.br

```brine
fn parse_port(s: str) -> Result[int, str]:
    if not s.is_digit():
        return Err(f"not a port number: {s}")
    return Ok(int(s))


fn main() -> Result[(), str]:
    let port = parse_port("80x")?
    print(f"listening on {port}")
    return Ok(())
```

Output (stderr, exit code 1)

```text
error: not a port number: 80x
```

See [Option and Result](/language/error-handling/) for `?`. A panic exits with code 101, and `exit(code)` ends the program at once from anywhere.

Caution

In Brine 0.4.0, `brine check` doesn’t check `main`’s signature. A `main` that returns something else (a `str`, `Result[int, str]`) passes `brine check` and is rejected by `brine run` and `brine build` with [E0706](/reference/errors/#e0706).

## Functions aren’t values (yet)

[Section titled “Functions aren’t values (yet)”](#functions-arent-values-yet)

A function name can only be called. It can’t be stored in a variable, passed as an argument or returned; first-class functions are planned.

```brine
fn square(x: int) -> int:
    return x * x


fn main():
    let f = square
    print(f(3))
```

```text
error[E0310]: `square` is a function; functions can't be used as values yet
 --> main.br:5:13
  |
5 |     let f = square
  |             ^^^^^^ call it with `(...)`
  = run `brine explain E0310` for more about this error
error[E0303]: `f` is a variable of type `?`, not a function
 --> main.br:6:11
  |
6 |     print(f(3))
  |           ^ not callable
  = run `brine explain E0303` for more about this error
error: could not compile due to 2 errors
```

To choose behavior at run time, use an [enum](/language/enums-and-match/) and `match` on it.

## Rules

[Section titled “Rules”](#rules)

* Every parameter has a type; the return type follows `->` (none means `()`).
* Parameters are read-only. `mut p: T` is a changeable local copy; `ref p: T` is the caller’s variable, and the caller writes `ref` too.
* `let r = ref v` makes `r` another name for the variable `v`.
* References can’t be stored or returned, so they never dangle.
* A variable can’t be passed as `ref` twice in one call.
* An expression that changes a variable can’t read it elsewhere or change it again.
* `main` returns nothing, an `int` exit code, or `Result[(), E]`.
* Functions aren’t values.
