Features

A type system that holds at runtime, concurrency that genuinely parallelises, a full object model, pattern matching, and a standard library that covers real work. Here is what each of those looks like in code.

Type system

Types that hold at runtime

Types are enforced before your program runs and stay enforced while it runs. They are not annotations a runtime ignores, and they are not erased before execution the way TypeScript erases them, so generics persist and a runtime type check on a parameterised type actually works. Values are non-null unless you opt in with ?T, and any is the deliberate escape hatch for the places that genuinely need dynamic behaviour.

import io;

# Non-null by default. Opt into a missing value with ?T.
func lookup(int id): ?string {
    if (id == 1) {
        return "Mara";
    }
    return null;
}

let name = lookup(2) ?? "guest";
io.println(name);

Functions

Overloading, a pipe operator, partial application, decorators

Functions are overloaded by argument count and type, so one name can take an int or a string and the right body runs. Decorators wrap behaviour rather than sitting inert as metadata, and the pipe operator and partial application keep data transformations readable.

import io;

# Overloading: same name, resolved by argument type.
func describe(int n): string {
    return "int ${n}";
}

func describe(string s): string {
    return "string ${s}";
}

io.println(describe(42));
io.println(describe("hi"));
import io;

func double(int n): int {
    return n * 2;
}

func add(int a, int b): int {
    return a + b;
}

# Partial application leaves a hole; the pipe feeds the result along.
let add10 = add(_, 10);
io.println(5 |> double |> add10);
import io;

# A decorator wraps the function. @memoize caches results.
@memoize
func fib(int n): int {
    if (n < 2) {
        return n;
    }
    return fib(n - 1) + fib(n - 2);
}

io.println(fib(30));

Concurrency

Async on goroutines, real parallelism

An async func starts a task on a goroutine; async.all waits for a batch to finish together. Requests and CPU-bound work run in true parallel, with no global lock and no single event loop to block. The same model powers the HTTP server in the standard library.

import io;
import async;

async func fetch(string name): string {
    await async.sleep(50);
    return "${name} ready";
}

let results = await async.all([fetch("users"), fetch("orders"), fetch("stats")]);
for (r in results) {
    io.println(r);
}

Objects

A full object model

Classes, interfaces, inheritance, and generics, plus operator overloading and immutable types. Operators like + and == dispatch to methods you define, and a value cast to a string goes through your own __string, so your types read naturally everywhere.

import io;

class Vec {
    int x;
    int y;

    func Vec(int x, int y) {
        this.x = x;
        this.y = y;
    }

    func __add(Vec other): Vec {
        return Vec(this.x + other.x, this.y + other.y);
    }

    func __string(): string {
        return "(${this.x}, ${this.y})";
    }
}

io.println(Vec(1, 2) + Vec(3, 4));

Pattern matching

Match over values, types, and enums

A match expression evaluates to the matched branch and covers every case, with default for the rest. It matches plain values, types, and enum variants that carry data, so dispatch on the shape of a value stays in one readable block.

import io;

func classify(int code): string {
    return match (code) {
        case 200 => "ok";
        case 404 => "missing";
        default => "error";
    };
}

io.println(classify(404));

Toolchain

One toolchain, not ten packages

A static type checker, an autoformatter, a test runner, a language server with a VS Code extension, a REPL, and a step debugger all ship with the toolchain. There is nothing to assemble from separate linter, formatter, test, and type-check packages, and they all agree on the same language.

  • geblang check type-checks and lints without running your code.
  • geblang fmt formats in place.
  • geblang test discovers and runs your test suites.
  • geblang build produces a single self-contained binary.

Standard library

A standard library that covers real work

HTTP server and client, WebSockets, SQLite, Postgres and MySQL, Redis, message brokers, crypto and JWT, JSON, YAML, TOML and XML, templating, datetime, math, and more. Most programs need no third-party packages at all.

For web applications, Gebweb, a separate web framework written in Geblang, builds on top of the standard library with routing, OpenAPI, auth, validation, and server-rendered views.

See it for yourself

Install the toolchain and write your first program in a few minutes, or browse runnable examples.