Types & values

Langoost has a small set of value types. Type annotations are optional, and values are strongly typed at runtime. A lightweight static checker also runs at compile time — see Static type checking below.

Value types

TypeDescriptionExample
int64-bit signed integer42, -7, 0
float64-bit IEEE-754 double3.14, -0.5, 1e10
boolBooleantrue, false
stringUTF-8 text"hello", 'world'
arrayOrdered list of any values[1, "two", true]
objectKey/value structure{x: 10, y: 20}
voidAbsence of a value (nil)nil
anyAccepts any type, unchecked
json / yaml / xmlString annotated as that data format{key: "val"}

Array types use a [] suffix on the element type: int[], string[].

Number literals

Integers can be written in several bases, with _ as a digit separator; floats support scientific notation:

let dec = 1_000_000
let hex = 0xDEAD_BEEF
let bin = 0b1010
let oct = 0o755
let f   = 1.5e-3

Strings

Single and double quotes are both accepted, with escapes \n, \t, \r, \", \', \\, \0:

let a = "hello"
let b = 'world'

Template strings

Backtick strings interpolate embedded expressions with ${...}:

let name = "Ada"
println(`Hello, ${name} — you have ${3 + 4} messages`)

Objects

Object literals map keys to values. Keys can be read with dot or bracket access; brackets also allow dynamic keys:

let user = {name: "alice", age: 30}
println(user.name)        // "alice"
println(user["age"])      // 30
user["role"] = "admin"    // add / update a field

Objects double as maps. To attach a named type, see classes & types.

nil and negative indexing

nil is the empty/void value. Arrays and strings support Python-style negative indices:

let xs = [10, 20, 30]
println(xs[-1])           // 30  (last element)
let missing = nil

Conversion

Coercion is explicit:

let n: int = toInt("42")
let f: float = toFloat(n)
let s: string = toString(n)
println(typeof(n))        // "int"

The json, yaml, and xml types are strings with special meaning — see the stdlib json module and the : json inline-literal syntax.

Static type checking

A lightweight, annotation-driven checker runs at compile time. It’s intentionally conservative — it catches obvious mistakes without getting in the way of dynamic code. It currently verifies that literals match their declared type in four places:

let n: int = "oops"          // compile error: expected int
fn area(w: float): float {
    return "nope"            // compile error: expected float
}
  • let x: T = literal
  • x = literal when x is a typed local or global
  • return literal from a function with a declared return type
  • typed parameter defaults

Enforcement covers only the primitive set int, float, string, bool, and array. Other annotations — json, any, class names, interfaces — pass through unchecked, so dynamic code keeps working. There is no type inference across expressions yet.