01

A small toy
language.

toy is a general purpose language which is statically typed, compiled, and garbage collected.

It aims to be ergonomic and performant but the main goal is for me to learn about language design and compiler development.

02

Features

A modern type system over value types, with the ergonomics you expect and none of the ceremony.

Type inference

Bind a value with := and its type is inferred. Annotate the boundaries and let the body follow.

order.toy
fn main() -> int {    price := 20        # inferred int    quantity := 3    return price * quantity}

Pattern matching

Enums hold one of several variants. match destructures them, checked for exhaustiveness at compile time.

shapes.toy
pub enum Shape { Circle(int), Square(int) }pub fn area(shape: Shape) -> int {    match shape {        .Circle(r) -> 3 * r * r,        .Square(side) -> side * side,    }}

Generics

Generic structs and functions are monomorphized. Pair[int, int] reifies to an ordinary struct — no boxing.

pair.toy
struct Pair[A, B] { left: A, right: B }fn main() -> int {    point := Pair[int, int] { left: 3, right: 39 }    return point.left + point.right}

Protocols

A protocol is a set of method signatures. Conform a type with impl Square has Area and call its methods directly.

area.toy
protocol Area {    fn area(self) -> int}struct Square { side: int }impl Square has Area {    fn area(self) -> int { self.side * self.side }}

Pipes

x |> f(a) is f(x, a): the value on the left becomes the first argument, so a chain of calls reads in the order it runs.

pipeline.toy
fn double(x: int) -> int { x * 2 }fn add(a: int, b: int) -> int { a + b }fn main() -> int {    score := 3        |> double        |> add(36)     # add(double(3), 36)    return score}

Closures

A lambda fn(x) { .. } captures the variables it names by reference. add(10, _) is short for a lambda, |> .m() pipes into a method, and a mut parameter writes to the caller's variable.

closures.toy
import std/vecfn add(a: int, b: int) -> int { a + b }fn bump(mut n: int) { n = n + 1 }fn main() -> int {    count := 0    total := [5, 1, 4, 2, 3]        |> .filter(fn(x) { x > 2 })        |> .map(add(10, _))    # fn(x) { add(10, x) }        |> .fold(0, fn(sum, x) {            count = count + 1  # shared with main, not a copy            sum + x        })    bump(count)                # count is now 4    return total + count}

No null

Option[T] and Result[T, E] are ordinary enums. The postfix ? unwraps a value or returns early on the empty case.

total.toy
pub fn total(a: Option[int], b: Option[int]) -> Option[int] {    x := a?    y := b?    Option.some(x + y)}
03

Install

toy currently has to be built from source.

04

Learn

Ready to go deeper? Walk the language tour, browse the reference, or read the source.

toy a small toy language