Language GuideThis is the reference for Seen's syntax and semantics.

Language Guide

This is the reference for Seen's syntax and semantics.

Comments

Seen supports // line comments and block comments delimited by standalone /// lines:

// Single-line comment

///
Anything between standalone delimiter lines is ignored by the lexer.
Use this for longer notes without prefixing every line.
///

/// text is still treated as a line comment; block delimiters must be the only non-whitespace text on the line.

Variables

Immutable (let)

let name = "Alice"
let age = 30
let pi = 3.14159

Mutable (var)

var count = 0
count = count + 1

Value binding (val)

val MAX_SIZE = 1024

Constants and statics

const PI = 3.14159265
static var instance_count = 0

Type Annotations

Types can be explicit or inferred:

let x: Int = 42
let y: Float = 3.14
let s: String = "hello"
let b: Bool = true
let c: Char = 'A'

Built-in Types

Type Description
Int 64-bit signed integer
Float 64-bit floating point
Bool Boolean (true/false)
String UTF-8 string
Char Unicode code point
Void No value
Never Function never returns

Functions

Basic function

fun greet(name: String) r: String {
    return "Hello, {name}!"
}

The r: syntax specifies the return type.

Void functions (no return)

fun logMessage(msg: String) {
    println(msg)
}

Fat arrow syntax

For single-expression bodies:

fun double(x: Int) r: Int => x * 2

Multiple parameters

fun add(a: Int, b: Int) r: Int {
    return a + b
}

Default parameters are not yet supported — use overloads or optional types.

Facade Components

Facade component functions use the contextual component form. Inside a component body, state, computed, and uiEffect declare UI-local state, derived values, and explicit side-effect blocks:

component Counter(title: String) {
    state count: Int = 0
    computed label: String = title + ": " + count.toString()

    uiEffect {
        println(label)
    }
}

Component calls support named arguments and trailing or named slot blocks for declarative APIs. Dynamic child lists should provide stable keys so frontend and editor diagnostics can catch missing or duplicate child identity.

Control Flow

if / else

if x > 0 {
    println("positive")
} else {
    println("non-positive")
}

if as expression

let result = if x > 0 { "positive" } else { "non-positive" }

while loop

var i = 0
while i < 10 {
    println("{i}")
    i = i + 1
}

for-in loop

for item in items {
    println("{item}")
}

Range-based for

for i in 0..10 {
    println("{i}")  // 0 through 9
}

for i in 0..=10 {
    println("{i}")  // 0 through 10
}

loop (infinite)

loop {
    let input = readLine()
    if input == "quit" {
        break
    }
}

break and continue

for i in 0..100 {
    if i == 50 { break }
    if i % 2 == 0 { continue }
    println("{i}")
}

Pattern Matching

when expression

let result = when value {
    is 1 => "one"
    is 2 => "two"
    is 3 => "three"
    else => "other"
}

match on enums

when shape {
    is Circle(r) => println("Circle with radius {r}")
    is Rectangle(w, h) => println("Rectangle {w}x{h}")
}

Classes

Basic class

class Point {
    var x: Float
    var y: Float

    static fun new(x: Float, y: Float) r: Point {
        return Point { x: x, y: y }
    }

    fun distanceTo(other: Point) r: Float {
        let dx = this.x - other.x
        let dy = this.y - other.y
        return sqrt(dx * dx + dy * dy)
    }
}

Constructors

Use static fun new(...) by convention:

let p = Point.new(3.0, 4.0)

this keyword

Instance methods access fields via this:

fun getX() r: Float {
    return this.x
}

Inheritance

class Shape {
    var name: String

    fun describe() r: String {
        return "Shape: {this.name}"
    }
}

class Circle extends Shape {
    var radius: Float

    fun area() r: Float {
        return 3.14159 * this.radius * this.radius
    }
}

Sealed classes

sealed restricts subclassing to the same compilation/package boundary used by the compiler's type checks:

sealed class Expr {
}

Structs

Data struct (value type)

data struct Color(r: Int, g: Int, b: Int)

This is a compact value type declaration.

Regular struct (alias for class)

struct Config {
    var width: Int
    var height: Int
    var title: String
}

Enums

Simple enum

enum Direction {
    North
    South
    East
    West
}

Data-carrying enum

enum Shape {
    Circle(radius: Float)
    Rectangle(width: Float, height: Float)
    Triangle(base: Float, height: Float)
}

Using enums

let dir = Direction.North
let shape = Shape.Circle(5.0)

Traits and impl

Defining a trait

trait Printable {
    fun display() r: String
}

Implementing a trait

impl Printable for Point {
    fun display() r: String {
        return "({this.x}, {this.y})"
    }
}

Trait constraints on generics

fun printItem<T: Printable>(item: T) {
    println(item.display())
}

Generics

Generic functions

fun max<T>(a: T, b: T) r: T {
    if a > b { return a }
    return b
}

Generic classes

class Stack<T> {
    var items: Array<T>

    static fun new() r: Stack<T> {
        return Stack { items: Array<T>() }
    }

    fun push(item: T) {
        this.items.push(item)
    }

    fun pop() r: T {
        return this.items.pop()
    }

    fun isEmpty() r: Bool {
        return this.items.length() == 0
    }
}

Generic constraints

fun sort<T: Ord>(arr: Array<T>) r: Array<T> {
    // T must implement Ord
}

Closures

let doubled = apply(nums, |x| x * 2)
let filtered = items.filter(|x| x > 0)

Closures use |params| expression syntax. Currently no-capture (function pointer) semantics.

Nullable Types

Optional types with T?

var name: String? = null
name = "Alice"

Safe access with ?.

let len = name?.length()  // returns null if name is null

Null coalescing with ??

let displayName = name ?? "Anonymous"

if-let pattern

if let n = name {
    println("Name is {n}")
}

Result Types

Result<T, E>

fun divide(a: Int, b: Int) r: Result<Int, String> {
    if b == 0 {
        return Err("division by zero")
    }
    return Ok(a / b)
}

The ? operator

Propagates errors to the caller:

fun compute() r: Result<Int, String> {
    let x = divide(10, 2)?
    let y = divide(x, 3)?
    return Ok(x + y)
}

Allocation errors

Allocation-heavy APIs expose fallible try* forms using the same Result<T, E> style. AllocError carries the requested size plus current runtime memory-budget state.

import core.result.{Result, Ok}
import core.unit.{Unit}
import memory.allocation.{AllocError, ensureAllocationBudget}

fun prepareBuffer(bytes: Int) r: Result<Unit, AllocError> {
    ensureAllocationBudget(bytes)?
    return Ok(Unit{})
}

Set SEEN_MEMORY_LIMIT_BYTES to enforce a process allocation budget from the outside, or call setMemoryLimitBytes(bytes) inside a program.

try / catch

try {
    let result = riskyOperation()
    println("Success: {result}")
} catch e {
    println("Error: {e}")
}

String Interpolation

Use {expression} inside double-quoted strings:

let name = "World"
println("Hello, {name}!")

let x = 42
println("The answer is {x}")

let p = Point.new(3.0, 4.0)
println("Distance: {p.distanceTo(Point.new(0.0, 0.0))}")

Arrays and Collections

Array literals

let nums = [1, 2, 3, 4, 5]
let names = ["Alice", "Bob", "Charlie"]

Array operations

var arr = Array<Int>()
arr.push(1)
arr.push(2)
let first = arr.get(0)
let len = arr.length()

Array with initial size

let zeros = Array<Int>.withLength(100)

HashMap

var map = HashMap<String, Int>()
map.insert("alice", 30)
map.insert("bob", 25)
let age = map.get("alice")

Byte Buffers and Algorithms

let bytes = ByteBuffer.withCapacity(256)
bytes.reserve(1024)
bytes.push(255)

let raw = Int32Buffer.withCapacity(128)
raw.push(42)

let values = [5, 1, 3]
unstableSortInt(values)
let slot = lowerBoundInt(values, 3)

let scores = Array<Float>()
scores.push(3.5)
scores.push(1.25)
unstableSortFloat(scores)

See the Collections API for Vec, BTreeMap, ByteBuffer, primitive buffers, sort/search helpers, priority queues, and more.

Ranges

0..10      // exclusive: 0, 1, 2, ..., 9
0..=10     // inclusive: 0, 1, 2, ..., 10

Operators

Arithmetic

+, -, *, /, %

Comparison

==, !=, <, <=, >, >=

Logical

and, or, not (also &&, ||, !)

Bitwise

&, |, ^, ~, <<, >>

Compound assignment

+=, -=, *=, /=, %=, &=, |=, ^=, <<=, >>=

Type Casting

Use as for type conversions:

let x: Int = 42
let f = x as Float
let s = x as String

Modules and Imports

Import

import io
import collections.HashMap

Visibility

pub makes declarations visible outside the module. Capitalized declaration names are also public by convention, so both forms remain valid:

pub fun publicFunction() {
    // accessible from other modules
}

class PublicByName {
    // capitalized declarations are externally visible
}

fun privateFunction() {
    // only accessible within this module
}

Package-private declarations are visible inside the same package and rejected from outside-package imports.

Package imports

import package_name
import package_name::src::module.{Symbol}
import local_module.{Thing}

Prebuilt package artifacts expose declarations through interface.index.tsv and link implementation objects through objects.tsv.

Effects and Capabilities

Functions can declare required capabilities with effect(Token):

fun readConfig(token: FileToken) effect(FileToken) r: String {
    return readText("config.toml")
}

Effects propagate through calls; missing or wrong capability tokens are diagnosed by the compiler.

Annotations

Annotations start with @ and attach metadata to declarations:

@using("libm")
extern fun cos(x: Float) r: Float

@operator("+")
fun addVec(a: Vec2, b: Vec2) r: Vec2 {
    return Vec2.new(a.x + b.x, a.y + b.y)
}

Common annotations include @using, @operator, @export, @cfg, @compute, @derive, and @reflect.

Operator Overloading

class Vec2 {
    var x: Float
    var y: Float

    operator fun +(other: Vec2) r: Vec2 {
        return Vec2.new(this.x + other.x, this.y + other.y)
    }

    operator fun *(scalar: Float) r: Vec2 {
        return Vec2.new(this.x * scalar, this.y * scalar)
    }
}

Unsafe Blocks

For low-level operations that bypass safety checks:

unsafe {
    let ptr = transmute(address)
    // raw pointer operations
}

Defer

Execute cleanup code when leaving a scope:

fun processFile(path: String) {
    let file = File.open(path)
    defer { file.close() }

    // file is automatically closed when scope exits
    let content = file.readContent()
}

errdefer

Only executes if the scope exits via error:

fun allocateResource() r: Result<Resource, String> {
    let res = acquire()
    errdefer { release(res) }

    let configured = configure(res)?  // if this fails, res is released
    return Ok(configured)
}

Type Aliases

type Callback = Fun
type StringList = Array<String>

Distinct types

distinct Meters = Float
distinct Seconds = Float

// Meters and Seconds are incompatible even though both are Float

Extension Methods

extension fun String.isBlank() r: Bool {
    return trim(this) == ""
}

Next Steps

On this page
Architected in Kotlin. Rendered with Materia. Powered by Aether.
© 2026 Yousef.