# Built-in functions

> Every function Brine provides without an import, from print and len to math, conversions, embed(), files and processes, and which of them can run inside par.

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

These functions are always available, with no import. Files and processes report failure as `Result` or `Option` values, never by crashing. A few built-ins change the world outside the program, and those can’t be called inside a `par` body ([E0503](/reference/errors/#e0503)).

| Function                                                        | Result             |                                        |
| --------------------------------------------------------------- | ------------------ | -------------------------------------- |
| `print(a, b, ..., sep=" ", end="\n")`                           |                    | write to stdout                        |
| `eprint(a, b, ..., sep=" ", end="\n")`                          |                    | write to stderr                        |
| `len(x)`                                                        | `int`              | array, string (bytes) or map           |
| `abs(x)`                                                        | same as `x`        | any number                             |
| `min(a, b)`, `max(a, b)`                                        | same as `a`        | two numbers of the same type           |
| `sqrt`, `sin`, `cos`, `tan`, `exp`, `log`                       | float              | one float                              |
| `floor`, `ceil`, `round`                                        | float              | one float                              |
| `pow(x, y)`                                                     | `float`            | two `float`s                           |
| `sum`, `product`, `min`, `max`, `any`, `all`                    |                    | over a generator: `sum(x for x in xs)` |
| `range(stop)`, `range(start, stop)`, `range(start, stop, step)` |                    | in `for` and comprehensions only       |
| `enumerate(xs)`                                                 | `[(int, T)]`       |                                        |
| `int(x)`, `float(x)`, `str(x)`, `i32(x)`, `u8(x)`, …            |                    | conversions                            |
| `ord(c)`, `chr(n)`                                              | `int`, `str`       | code points                            |
| `clock()`                                                       | `float`            | seconds, for timing                    |
| `args()`                                                        | `[str]`            | command-line arguments                 |
| `exit(code)`                                                    |                    | stop with an exit code                 |
| `panic(msg)`                                                    |                    | stop with a message                    |
| `embed("file")`                                                 | `str`              | a file’s text, read at compile time    |
| `read_file(path)`                                               | `Result[str, str]` |                                        |
| `write_file(path, text)`                                        | `Result[(), str]`  |                                        |
| `file_exists(path)`                                             | `bool`             |                                        |
| `getenv(name)`                                                  | `Option[str]`      |                                        |
| `run(cmd)`                                                      | `Result[int, str]` | run a program and wait for it          |

The [os module](/language/os-module/) has more for files, directories and processes, and [world](/parallelism/overview/) is for programs that run as many processes.

## Printing

[Section titled “Printing”](#printing)

`print` writes its arguments separated by `sep` (default `" "`) and followed by `end` (default `"\n"`). `eprint` does the same on stderr.

```brine
fn main():
    print("a", 1, 2.5, true)
    print([1, 2], ("x", 3), {"k": "v"}, Some("s"))
    print("no newline", end="")
    print(" | then", 1, 2, sep="-")
    print()
    eprint("this goes to stderr")
```

Output

```text
a 1 2.5 true
[1, 2] ("x", 3) {"k": "v"} Some("s")
no newline | then-1-2


this goes to stderr
```

* A string argument prints as its text. Strings inside arrays, tuples, maps, structs and enums print quoted, so `["a"]` is distinguishable from `[a]`.
* Every value prints except `()` on its own (`Ok(())` prints fine). Structs print as `Point(x=1, y=2)` and enum variants as `Shape.Circle(radius=1.0)`.
* `print()` with no arguments prints an empty line.
* `sep` and `end` must be strings and are the only keyword arguments.

## Numbers

[Section titled “Numbers”](#numbers)

```brine
fn main():
    print(abs(-3), abs(-2.5), min(3, 7), max(2.5, 1.0))
    print(sqrt(2.0), pow(2.0, 10.0), exp(1.0), log(10.0))
    print(sin(0.0), cos(0.0), tan(0.0))
    print(floor(-1.5), ceil(1.2), round(2.5), round(-2.5), int(round(2.6)))
    print(sqrt(-1.0), log(0.0))
```

Output

```text
3 2.5 3 2.5
1.4142135623730951 1024.0 2.718281828459045 2.302585092994046
0.0 1.0 0.0
-2.0 2.0 3.0 -3.0 3
nan -inf
```

* `abs` works on any number and returns the same type. `abs` of the most negative integer overflows and panics.
* `min(a, b)` and `max(a, b)` need two numbers of the **same** type: `min(1, 2.0)` is error E0301. A literal adapts to the other argument (`min(x, 3)` with an `i32` `x` is fine). They don’t compare strings.
* `sqrt`, `sin`, `cos`, `tan`, `exp`, `log` (natural log), `floor`, `ceil` and `round` take a `float` or `f32` and return the same type. An integer literal is read as a float (`sqrt(4)` is `2.0`); an integer variable needs `float(n)`.
* `pow(x, y)` takes and returns `float` (`f64`).
* `floor`, `ceil` and `round` return floats. Convert with `int(...)` for an integer. `round` rounds halves away from zero (`round(2.5)` is `3.0`), not to even as Python does.
* Math on floats follows IEEE 754: `sqrt(-1.0)` is `nan` and `0.0 / 0.0` is `nan`, with no panic. Integer division by zero panics.

`len`, `abs`, `min` and `max` can also appear in `requires`, `ensures` and other [contracts](/proofs/overview/).

## Reductions

[Section titled “Reductions”](#reductions)

`sum`, `product`, `min`, `max`, `any` and `all` with one generator argument fold a sequence without building an array: `sum(x * x for x in xs)`, `any(w == "" for w in words)`. `min` and `max` of an empty sequence panic. See [arrays](/language/arrays/#reductions).

## Ranges and `enumerate`

[Section titled “Ranges and enumerate”](#ranges-and-enumerate)

```brine
fn main():
    print([i for i in range(5)], [i for i in range(2, 5)], [i for i in range(10, 0, -3)])
    print([i for i in 0..4], [i for i in 0..=4], [i for i in 5..2])
    for i, w in enumerate(["a", "b"]):
        print(i, w)
    print(enumerate(["x", "y"]))
```

Output

```text
[0, 1, 2, 3, 4] [2, 3, 4] [10, 7, 4, 1]
[0, 1, 2, 3] [0, 1, 2, 3, 4] []
0 a
1 b
[(0, "x"), (1, "y")]
```

* `a..b` counts from `a` up to `b - 1`, `a..=b` includes `b`. `range(...)` works as in Python, including a negative step; a step of 0 panics.
* Ranges exist only as the iterable of a `for` loop or comprehension. `let r = range(0, 3)` is error E0312; write `[i for i in 0..3]` for an array.
* `enumerate(xs)` returns an array of `(index, element)` tuples.

## Conversions

[Section titled “Conversions”](#conversions)

There are no implicit conversions. Call the type as a function:

```brine
fn main():
    let n = 7
    let x = 2.9
    print(float(n) / 2.0, int(x), int(-x), int(true))
    print(str(n) + "!", str([1, 2]), int("42") + 1, float("2.5"))
    let small: u8 = u8(200)
    print(i32(n) + i32(1), small)
```

Output

```text
3.5 2 -2 1
7! [1, 2] 43 2.5
8 200
```

* `int(x)` of a float truncates toward zero. A float that doesn’t fit, or `nan`, panics.
* `i32(n)`, `u8(n)` and the other sized types check the range and panic if the value doesn’t fit: `integer conversion out of range for u8`.
* `int(true)` is 1. There is no `bool(...)`: write `n != 0`.
* `str(x)` works for any printable value. `int(s)` and `float(s)` parse a string and panic on bad input. See [strings](/language/strings/#converting-to-and-from-strings).
* `ord(c)` is the code point of a one-character string and `chr(n)` the string for a code point.

## The program: `args`, `exit`, `panic`, `clock`

[Section titled “The program: args, exit, panic, clock”](#the-program-args-exit-panic-clock)

greet.br

```brine
fn main() -> int:
    let a = args()
    if len(a) == 0:
        eprint("usage: greet <name>...")
        return 2
    for name in a:
        print(f"hello, {name}")
    return 0
```

```sh
brine run greet.br -- ann "bob smith"
```

Output

```text
hello, ann
hello, bob smith
```

* `args()` is the command-line arguments, without the program’s own name. With `brine run`, they go after `--`.
* `main` may return nothing (exit code 0), an `int` (the exit code), or a `Result[(), str]` (an `Err(e)` prints `error: e` and exits with 1). See [functions](/language/functions/).
* `exit(code)` stops the program at once with that exit code.
* `panic(msg)` stops the program with a message and the source location, and exit code 101. Use it for bugs, not for expected failures (return a `Result` for those; see [error handling](/language/error-handling/)).
* `clock()` is a monotonic time in seconds as a `float`. Subtract two readings to time something:

```brine
fn work(n: int) -> int:
    var total = 0
    for i in 0..n:
        total += i % 7
    return total


fn main():
    let t0 = clock()
    let r = work(10_000_000)
    let dt = clock() - t0
    print(r, f"{dt:.3f} s")
```

Output

```text
29999994 0.013 s
```

(The time differs from run to run.)

```brine
fn main():
    let n = 3
    panic(f"bad value: {n}")
```

Output

```text
panic: bad value: 3
  --> main.br:3:5
```

## `embed`

[Section titled “embed”](#embed)

`embed("path")` is a `str` holding a file’s text, read when the program is **compiled**, so the program doesn’t need the file at run time. Use it for help text, templates and test data:

```brine
const HELP = embed("help.txt")


fn main():
    print(HELP, end="")
```

* The path must be a string literal, relative to the directory of the `.br` file that contains the call.
* The file must exist when you compile and be UTF-8 text. `\r\n` line endings become `\n`.
* It works in `const`s, as above, and anywhere an expression can go.
* A missing file or a non-literal path is error E0707:

```text
error[E0707]: cannot embed `nope.txt`
 --> main.br:2:17
  |
2 |     print(embed("nope.txt"))
  |                 ^^^^^^^^^^ no file at `nope.txt`
  |
  = help: the path is relative to the directory of the file that contains the `embed`
  = run `brine explain E0707` for more about this error
error: could not compile due to 1 error
```

## Files, environment and processes

[Section titled “Files, environment and processes”](#files-environment-and-processes)

```brine
fn main():
    match read_file("missing.txt"):
        case Ok(text):
            print(len(text.lines()), "lines")
        case Err(e):
            print("error:", e)
    print(write_file("out.txt", "hi\n"), file_exists("out.txt"), read_file("out.txt"))
    print(getenv("NO_SUCH_VARIABLE"), getenv("PATH").is_some())
    print(run(["no-such-program"]))
```

Output

```text
error: cannot read missing.txt: No such file or directory
Ok(()) true Ok("hi\n")
None true
Err("cannot run no-such-program: program not found")
```

* `read_file(path)` returns the whole file as `Ok(text)`, or `Err(message)`. The file must be UTF-8 text; otherwise it’s an `Err` (`cannot read b.bin: the file is not valid UTF-8 text`).
* `write_file(path, text)` creates or replaces the file.
* `file_exists(path)` is `true` for an existing file or directory.
* `getenv(name)` is `Some(value)` or `None`.
* `run(cmd)` starts `cmd[0]` (searched on `PATH`) with the rest as arguments, waits for it, and returns `Ok(exit code)`. The program shares the terminal: its output goes straight to yours. It’s `Err` only if the program can’t start. To capture output, run it in the background or pass environment variables, use [`os.spawn`](/language/os-module/#processes).

With `?` these read naturally in a function that returns `Result`:

```brine
fn line_count(path: str) -> Result[int, str]:
    let text = read_file(path)?
    return Ok(len(text.lines()))


fn main() -> Result[(), str]:
    write_file("notes.txt", "one\ntwo\nthree\n")?
    print(line_count("notes.txt")?)
    return Ok(())
```

Output

```text
3
```

## Inside `par`

[Section titled “Inside par”](#inside-par)

`par` bodies run in an unpredictable order, so built-ins whose effects would depend on that order are compile errors there:

| Allowed in `par`                                                                                                                                                            | Not allowed in `par` (E0503) |
| --------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ---------------------------- |
| `print`, `eprint` (lines from different iterations may come in any order), `panic`, `read_file`, `file_exists`, `getenv`, `clock`, `args`, and everything else on this page | `write_file`, `run`, `exit`  |

```brine
fn main():
    par for i in 0..4:
        let r = write_file(f"out{i}.txt", "hi")
```

```text
error[E0503]: `write_file` can't be called inside a `par` body
 --> main.br:3:17
  |
3 |         let r = write_file(f"out{i}.txt", "hi")
  |                 ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ not allowed here
  |
  = help: its effects would happen in an unpredictable order; do it before or after the `par`
  = run `brine explain E0503` for more about this error
error: could not compile due to 1 error
```

Compute the results in parallel, then write them afterwards. Some `os` functions have the same rule; see [the os module](/language/os-module/#inside-par).

Related: [strings](/language/strings/), [arrays](/language/arrays/), [the os module](/language/os-module/), [C interop](/language/c-interop/).
