Start here
Quickstart
Get from a blank file to a running program.
Open quickstart →02Tutorials
Follow guided guides through the core language features.
Read tutorials →03Language reference
Read the spec, types, declarations, expressions, and runtime behaviour.
Open reference →04Blog
Design notes, RFC write-ups, and where the language is headed next.
Read the blog →Examples
Strings stay lightweight
Use string interpolation directly instead of building formatting helpers first.
fun main() {
let name = "Ada";
let score = 98;
println("${name}: ${score}");
}
ReferencesShared state is explicit
When two closures need the same mutable state, aliasing is visible in the source.
fun main() {
var n = 0;
let r: &var i64 = &var n;
let inc = () -> () { r += 1; };
inc();
}
ADTsEnums drive control flow
Pattern matching stays central: model the alternatives, then make each case explicit.
fun describe(v: Perhaps<i64>) -> String {
match v {
Perhaps::Some { value: n } => "${n}",
Perhaps::None => "empty",
}
}
GenericsWrite it once, for any T
A generic function like first<T> works over any item type, with no boilerplate specialization.
fun first<T>(items: T[]) -> Perhaps<T> {
if (items.len() == 0) {
return Perhaps::None;
}
return Perhaps::Some { value: items[0u64] };
}
AspectsCapabilities without inheritance
An aspect declares a capability, extend attaches it to a type, and generic bounds can rely on it directly.
aspect Printable {
fun print(self);
}
extend Point: Printable {
fun print(self) {
println("(${self.x}, ${self.y})");
}
}
Error handling? propagates, .yolo() unwraps
Result and Perhaps share both: ? bubbles an Err up automatically, and .yolo() unwraps when you are sure.
fun double_parse(s: String) -> Result<i64, ParseError> {
let n = parse_positive(s)?; // returns Err immediately on failure
return Result::Ok { value: n * 2 };
}
fun main() {
println(double_parse("42").yolo()); // 84
}