The language

Make the domain
part of the program.

Ostrin is being shaped around a simple idea: important meaning should be represented by the language itself, not left as a convention for every programmer to remember.

design principlesstatic checkingscientific-first

01 / Physical quantities

Numbers are not the whole value.

A quantity has a magnitude and a dimension. Ostrin keeps the relationship visible through the type system, so derived values can be checked at compile time.

physics.ostrin
01fn velocity(distance: Quantity<Length>,
02          time: Quantity<Time>) -> Quantity<Length / Time> {
03    distance / time
04}
05
06speed = velocity(10 m, 2 s)
What this means: the result is not simply a floating-point number. It is a quantity whose dimension is Length / Time.

02 / Explicit state

Mutation has a visible cost.

Bindings are immutable by default. The mut marker gives changing state a clear place in the program and makes ownership decisions easier to inspect.

state.ostrin
01total = 0
02mut running_total = 0
03for value in values {
04    running_total = running_total + value
05}

03 / Failure as data

Errors should have a shape.

Option, Result and pattern matching keep success and failure in the type model. The compiler can then make missing cases visible instead of letting them disappear into control flow.

errors.ostrin
01fn load(id: Id) -> Result<Record, LoadError> {
02    try database.fetch(id)
03}
04
05match load(id) {
06    Ok(record) => print(record),
07    Err(error) => report(error)
08}

04 / Composable abstractions

Traits, generics and modules.

The language core includes records, enums, traits, generic functions, implementations and modules. These are the pieces that let a language move from examples to reusable software.

traits

Define shared behavior

Nominal traits describe what a type can do and provide a stable surface for library design.

generics

Preserve type information

Generic functions and bounds let abstractions stay precise without duplicating code.

modules

Organize a program

Visibility and module boundaries make larger codebases easier to navigate and evolve.

patterns

Make cases explicit

Enums and pattern matching give domain models a readable, checkable shape.

05 / Concurrency direction

Safe by default, explicit by design.

Ostrin's concurrency model uses channels, spawned tasks and immutable-by-default values. The interpreter and cooperative C runtime are deterministic; --native-threads enables OS threads, blocking channels and cooperative cancellation with the same API.

concurrency.ostrin
01channel = channel<Int>()
02producer = spawn {
03    channel.send(1)
04    channel.close()
05}
06for value in channel { print(value) }
Current status: deterministic execution, native threads, structured cancellation and cancelable channel waits are implemented. The browser playground is available; async external I/O and GPU execution remain roadmap work.