Skip to content

Types

Types are inferred, so a script rarely writes them. They show up where they help: a function’s signature, a refined type, a secret.

enum.sub
enum Shape { Circle(Int), Rect(Int, Int), Empty }
fn area(s: Shape) -> Int {
match (s) {
Circle(r) => 3 * r * r,
Rect(w, h) => w * h,
Empty => 0
}
}
print(area(Rect(3, 4)))

match must cover every case. Leave one out and sub check says which:

error[E0642]: this `match` does not cover: Empty
--> fail_enum.sub:4:3
|
4 | match (s) {
| ^^^^^^^^^^^ not every case is covered
= help: add those cases, or end with `_ => ...` to cover the rest

Exhaustiveness covers enums, Option, Result and Bool.

A refined type is a base type with a condition. A literal that breaks the condition is a compile error. A value that arrives at run time is checked where it is converted.

refined.sub
type Port = Int where 1..=65535
error ConfigError
error NotNumber <: ConfigError
error BadPort <: ConfigError
fn parse_port(text) -> Result<Port, ConfigError> {
let n = int(text) or {
return NotNumber("not a number")
}
Port(n) or {
return BadPort("out of range")
}
}
match (parse_port("8080")) {
Ok(p) => print("port", p),
Err(BadPort) => print("too big or too small"),
Err(ConfigError) => print("some other config problem")
}
match (parse_port("0")) {
Ok(p) => print("port", p),
Err(BadPort) => print("too big or too small"),
Err(ConfigError) => print("some other config problem")
}

error Name <: Family makes Name a subtype of Family. A handler can name the family or the exact case. OutOfRange and a few others are built in.

Secret<T> is not a subtype of T. A secret cannot reach print, log, a string or a record’s printout:

error[E0302]: a secret cannot be passed to `print`
--> fail_leak.sub:3:7
|
3 | print(token)
| ^^^^^ this is a secret
= help: a secret can only be compared with secret_eq(a, b) or passed to your own function that takes a `Secret`
let record = { name: "sub", port: 8080, ratio: 7 / 2.0 }
let moved = { ..record, port: 9090 } // a copy with one field changed
let total = fold([1, 2, 3], 0, fn(sum, n) { sum + n })
let found = find([1, 5, 8], fn(n) { n > 4 }) // an Option
print(unwrap_or(found, 0))
defer print("done") // runs when the enclosing function or script ends

List, Option and Result are generic. Your own functions are generalised by inference but cannot be annotated with type parameters yet.