---
title: Standard Library
canonical_url: https://mew-lang.org/stdlib/
sidecar_url: https://mew-lang.org/stdlib.md
content_hash: sha256:c20e0f4ba87db13e9b87e8816f7e32a6e18869f6cf5bc644b1316d7608bdfeec
tokens: 3325
uid: stdlib
reading_time_minutes: 12
---

Standard Library
# Standard Library

 
The standard library is Mew, not compiler machinery. It ships beside the compiler as `.mew` source, and every file in it is loaded into every compilation, so nothing in it needs a `#load`.

 
Being loaded is not the same as being in scope without a prefix. Those are decided separately: the shipped folder decides what is *loaded*, and each file's [namespace](https://mew-lang.org/language/namespaces.md) decides what it is *called*. Most of the library is namespaced, and is reached either by qualifying it or by importing it with `use`.

 
```mew
use std;
  
println(std.convert.itoa(42));   // qualified
```

 
```mew
use std;
use std.convert;
  
println(itoa(42));               // imported, so no prefix
```

 
## Always in scope

 
Four declarations are in the global namespace, so they need neither a `#load` nor a `use`.

 
    Name Why it is global     `Option<T>` A value that may be absent, described below   `Result<T, E>` An operation that may fail, described below   `Enumerable<T>` `for` resolves it by name   `Enumerator<T>` `for` resolves it by name    
 
`Enumerable<T>` and `Enumerator<T>` are described under [loops](https://mew-lang.org/language/control/loops.md), and carry the operators below.

 
## Sequences

 
`Enumerable<T>` carries seven operators as [members the interface supplies](https://mew-lang.org/language/interfaces.md#members-the-interface-supplies), so everything a `for` can walk has them, arrays included.

 
    Signature Answers     `map<U>(apply: fn(T) -> U) -> Enumerable<U>` Every element through `apply`   `filter(keep: fn(T) -> bool) -> Enumerable<T>` The elements `keep` says to keep   `fold<A>(seed: A, combine: fn(A, T) -> A) -> A` One value, `combine` run over every element   `find(keep: fn(T) -> bool) -> Option<T>` The first element `keep` says to keep   `any(keep: fn(T) -> bool) -> bool` Whether `keep` says to keep any of them   `count() -> i32` How many elements there are   `to_array() -> T[]` The elements, in an array    
 
Each takes a [lambda](https://mew-lang.org/language/lambdas.md), and `map` and `filter` answer with a sequence, so they chain.

 
```mew
use std;
  
pub type Person {
    pub field name: string;
    pub field age: i32;
}
  
let people = new Person[] {
    new Person { name: "ada", age: 11 },
    new Person { name: "patrik", age: 44 },
    new Person { name: "valentina", age: 46 },
};
  
let adults = people
    .filter(|p| p.age >= 18)
    .map(|p| p.name)
    .to_array();
  
println($"{adults.count}");
```

 
```
2
```

 
`map` and `filter` do no work when they are called. They answer with a sequence that walks the one it was built from, so a chain of them walks the source once, when something asks for the elements. The other five ask: `fold`, `count` and `to_array` walk all of it, and `find` and `any` stop at the first element that answers.

 
```mew
use std;
  
let values = new i32[] { 1, 2, 3, 4 };
  
println($"{values.fold(0, |total, n| total + n)}");
println($"{values.any(|n| n > 3)}");
println($"{values.find(|n| n > 2).unwrap()}");
```

 
```
10
true
3
```

 
`find` answers with an Option<T>, since a sequence need not hold what was asked for.

 
> [!NOTE]
> `to_array` walks the sequence twice, once to measure it and once to fill the array, because an array is fixed size. Everything else walks once.

 
## `std`

 
Writing text and stopping the program. Everything here needs `use std;` or the `std.` prefix.

 
    Signature Does     `print(value: string) -> void` Writes the text, with no line break   `println(value: string) -> void` Writes the text, followed by a line break   `eprint(value: string) -> void` The same, to standard error   `eprintln(value: string) -> void` The same, to standard error, with a line break   `panic(reason: string) -> void` Writes the reason and ends the program with exit code 1   `exit(code: i32 = 0) -> void` Ends the program with the given code, or with `0`    
```mew
use std;
  
println("Hello, world!");
  
print("no newline here");
println("");
```

 
`print` and `println` write to standard output, `eprint` and `eprintln` to standard error. Which one a program reaches for is which stream the reader is expected to be reading: output belongs on the first, and anything about the run itself on the second.

 
```mew
use std;
  
eprintln("reading the file took longer than expected");
println("done");
```

 
All four take text, so anything else is turned into text first. [Interpolation](https://mew-lang.org/language/primitives/text.md#string-interpolation) is how, and it is the only way a value becomes text, so what a program prints reads the same wherever it was written.

 
```mew
use std;
  
let name = "world";
let count = 3;
  
println($"{name} has {count}");
println($"{count}");
```

 
A value whose type is `any` cannot be printed. Interpolation has no text for it either, so say what it is first.

 
```mew
use std;
  
let boxed: any = 3;
  
println($"{boxed as i32}");
```

 
### Stopping early

 
`panic` is for the case where carrying on would be worse than stopping.

 
```mew
use std;
  
let count = 3;
  
if count < 0 {
    panic("a count cannot be negative");
}
```

 
```
Unhandled error: a count cannot be negative
```

 
The reason goes to standard error through `eprintln`, where the runtime's own failures go, so it does not land in output a caller is reading.

 
`exit` stops the program the same way without writing anything, and takes the code to stop with. Called with nothing it stops with `0`, the code for a run that went as intended.

 
```mew
use std;
  
let count = 3;
  
if count < 0 {
    exit(2);
}
```

 
Both carry the [noreturn](https://mew-lang.org/language/attributes.md#noreturn) attribute, so a path that ends in either owes no `return`. That is what makes `unwrap` below possible.

 
> [!NOTE]
> These two are the only way a Mew program stops early. There are no exceptions, so nothing catches a panic and nothing runs after it.

 
## `Option<T>` and `Result<T, E>`

 
Two global [unions](https://mew-lang.org/language/unions.md), for a value that may be absent and an operation that may fail. They exist so that neither has to be answered with `null`.

 
```mew
pub union Option<T> {
    none,
    some(T),
}
  
pub union Result<T, E> {
    ok(T),
    err(E),
}
```

 
A union is never `null` and a `match` has to handle every case, so a caller cannot read a value that is not there by forgetting to check.

 
```mew
use std;
  
pub fn head(values: i32[]) -> Option<i32> {
    if values.count == 0 {
        return Option<i32>::none;
    }
  
    return Option<i32>::some(values[0]);
}
```

 
```mew
match head(new i32[] { 3, 4 }) {
    .some(value) => {
        println($"{value}");
    },
    .none => {
        println("nothing there");
    },
}
```

 
```
3
```

 
### Reading one without a match

 
Both carry methods for the cases where a full `match` is more than the question needs.

 
    On `Option<T>` Gives     `is_some() -> bool` Whether there is a value   `is_none() -> bool` Whether there is not   `unwrap() -> T` The value, or a panic   `unwrap_or(fallback: T)` The value, or `fallback`   `or(other: Option<T>)` This option if it has a value, otherwise `other`   `map<U>(f: fn(T) -> U)` An `Option<U>`, with `f` run over the value   `and_then<U>(f)` What `f` answers, for chaining one option onto another   `filter(f: fn(T) -> bool)` This option if `f` answers true, otherwise `none`   `ok_or<E>(error: E)` A `Result<T, E>`, using `error` for `none`    
    On `Result<T, E>` Gives     `is_ok() -> bool` Whether it succeeded   `is_err() -> bool` Whether it failed   `unwrap() -> T` The value, or a panic   `unwrap_or(fallback: T)` The value, or `fallback`   `map<U>(f: fn(T) -> U)` A `Result<U, E>`, with `f` run over the value   `map_err<F>(f: fn(E) -> F)` A `Result<T, F>`, with `f` run over the error   `and_then<U>(f)` What `f` answers, for chaining one result onto another   `ok() -> Option<T>` The value as an option   `err() -> Option<E>` The error as an option    
```mew
use std;
  
pub fn divide(left: i32, right: i32) -> Result<i32, string> {
    if right == 0 {
        return Result<i32, string>::err("divide by zero");
    }
  
    return Result<i32, string>::ok(left / right);
}
```

 
```mew
println($"{divide(6, 2).unwrap_or(0)}");
println($"{divide(6, 0).unwrap_or(0)}");
println($"{divide(6, 0).err().unwrap_or("")}");
println($"{head(new i32[0]).ok_or<string>("empty").is_err()}");
```

 
```
3
0
divide by zero
true
```

 
`unwrap` reads the value and panics when there is none, so reach for it only where the absent case is a bug rather than something to handle.

 
```mew
println($"{divide(6, 2).unwrap()}");
println($"{divide(6, 0).unwrap()}");
```

 
```
3
Unhandled error: unwrapped a result that failed
```

 
> [!NOTE]
> The message names neither the value nor the error, because `T` and `E` can be any type and not every type has a text representation. Use `err()` and print that yourself when the reason matters.

 
### Working on the value without unwrapping it

 
`map`, `and_then` and `filter` take a [lambda](https://mew-lang.org/language/lambdas.md) and leave the absent or failed case alone, so a chain of them says what to do with a value without asking whether there is one at every step.

 
```mew
println($"{divide(6, 2).map(|n| n * 10).unwrap_or(0)}");
println($"{divide(6, 0).map(|n| n * 10).unwrap_or(-1)}");
println(divide(6, 0).map_err(|reason| $"failed: {reason}").err().unwrap_or(""));
println($"{divide(12, 2).and_then(|n| divide(n, 3)).unwrap_or(0)}");
```

 
```
30
-1
failed: divide by zero
2
```

 
`map` changes what is held, `and_then` chains one of these onto another and flattens the result, and `filter` on an `Option<T>` drops a value that does not answer the question.

 
```mew
use std;
  
let held: Option<i32> = .some(20);
  
println($"{held.filter(|n| n > 10).unwrap_or(0)}");
println($"{held.filter(|n| n > 100).is_none()}");
```

 
```
20
true
```

 
## `std.convert`

 
Conversions between text and numbers.

 
    Signature Does     `itoa(value: i32) -> string` The text of an `i32`   `atoi(value: string) -> Result<i32, ConvertError>` The `i32` a string spells, or why it does not    
```mew
use std;
use std.convert;
  
let text = itoa(42);
let number = atoi("42").unwrap_or(0);
```

 
Not every string spells a number, so `atoi` answers with a Result rather than a number. `ConvertError` says which way it failed.

 
```mew
pub union ConvertError {
    invalid,
    overflow,
}
```

 
```mew
use std;
use std.convert;
  
let text = "42";
  
match atoi(text) {
    .ok(value) => {
        println($"{value}");
    },
    .err(reason) => {
        println(reason.describe());
    },
}
```

 
    Given Answers     `"42"` `ok(42)`   `""` `err(invalid)`, "not a number"   `"abc"` `err(invalid)`, "not a number"   `"12abc"` `err(invalid)`, "not a number"   `"2147483648"` `err(overflow)`, "outside the range of an i32"    
 
`describe()` is the text of a `ConvertError`, for when the reason is going straight to a reader.

 
`itoa` cannot fail, so it hands back a `string` rather than a `Result`. It writes into a buffer of its own choosing, and twelve bytes is always enough for an `i32`, the widest being the eleven characters of `-2147483648`.

 
Printing a number needs neither of these. Interpolation already turns one into text, and `itoa` is for when the text itself is the value you want.

 
## `string`

 
The library adds three members to [string](https://mew-lang.org/language/primitives/text.md), which need no `use` because the type is always in scope.

 
    Signature Does     `is_empty() -> bool` Whether the string holds no characters   `parse_i32() -> Result<i32, ConvertError>` The `i32` this string spells, or why it does not   `string::join(separator: string, parts: ...string) -> string` The parts joined, separated   `string::join(separator: string, items: Enumerable<string>) -> string` The same, for a sequence rather than a list of arguments    
 
`is_empty` answers what `== ""` answers, with a name on it.

 
```mew
use std;
  
let name = "";
  
if name.is_empty() {
    println("no name given");
}
```

 
`parse_i32` is `atoi` written as a member, for when the string is what you have in hand.

 
```mew
use std;
  
let read = "42".parse_i32().unwrap_or(0);
  
println($"{read}");
```

 
`join` is static, so it is named on the type. One form takes anything a `for` can walk, an array included; the other [gathers](https://mew-lang.org/language/functions.md#gathering-what-is-left) the parts written at the call.

 
```mew
use std;
  
let names = new string[] { "one", "two", "three" };
  
println(string::join(", ", names));
println(string::join(", ", "one", "two", "three"));
```

 
## Native code

 
The library is ordinary Mew. It reaches the [platform](https://mew-lang.org/language/platform.md) the way your own code does, so `println` calls `Console::WriteLine` and `atoi` calls `Int32::TryParse`. Nothing in it is `external`, and it carries no attribute you could not write yourself.

 
> [!IMPORTANT]
> This surface is expected to change, and to grow. What belongs in the language, in the library that ships with it, and in a package someone installs has not been settled, so treat this as what exists today rather than as a stable surface.