Classes & types

Langoost supports objects, named types, and classes with single inheritance.

Objects

The simplest structured value is an object literal — keys mapped to values, accessed with dot or bracket notation:

let point = {x: 3, y: 4}
println(point.x)          // 3
point["y"] = 5            // update, or add a new key

Keys may also be written as string literals, which is handy for keys that aren’t identifiers (e.g. building queries):

let update = {"$set": {status: "active"}}

Objects are also Langoost’s map type. See types & values.

Type declarations

Give an object shape a name with type. This documents the structure and lets you construct values with Name{...}:

type User = {
    id: int,
    name: string,
    email: string,
}

let u = User{id: 1, name: "alice", email: "alice@example.com"}
println(u.name)           // "alice"

Types describe structure; fields are not enforced at runtime (duck typing).

Classes

A class groups methods. Construct an instance with ClassName{...} (setting any fields), then call its methods with dot syntax:

class Counter {
    fn increment() {
        self.count += 1
        return self.count
    }
    fn value() {
        return self.count
    }
}

let c = Counter{count: 0}
c.increment()
c.increment()
println(c.value())        // 2

Inside a method, self refers to the instance.

Inheritance

A class can extend one parent and call the parent’s implementation with super:

class Animal {
    fn speak() {
        return "..."
    }
    fn describe() {
        return "I say " + self.speak()
    }
}

class Dog extends Animal {
    fn speak() {
        return "woof"
    }
}

let d = Dog{}
println(d.describe())     // "I say woof"

Interfaces

An interface names a set of methods a value must provide. Interfaces are checked at runtime with the is and as operators:

interface Reader {
    fn read()
    fn close()
}

fn consume(x) {
    if x is Reader {          // → bool
        let r = x as Reader   // → x, or throws if it doesn't satisfy Reader
        process(r.read())
        r.close()
    }
}

x is Reader returns a bool; x as Reader returns the value if it satisfies the interface, or throws {kind: "InterfaceMismatch", message, want, got} otherwise. The check walks a class’s parent chain. (Generics are deferred — without static type checking they would be cosmetic.)

Notes

Langoost classes are intentionally small. There are no constructors (initialize fields in the Name{...} literal), and no static members or visibility modifiers. For error types and recoverable failures, see error handling.