Docs/Language

Language

Types & nullability

GitHub

Scalars, non-null by default, T?, flow narrowing, and force-unwrap.

Normative rules: RFC-002. MVP keywords and surface: RFC-001 §6.0.

Scalars you will see first

TypeNotes
IntInteger (overflow policy is documented in RFCs; prefer checked ops in dev)
FloatIEEE-754 double; NaN and infinities follow the host C double rules
Booltrue / false
StringImmutable C-string bytes (no embedded NUL; indices are UTF-8 bytes)
Array<T>Growable array — see Arrays
Task<T>Result of an async computation; consume with await
TaskHandle<T>Handle returned by spawn; consume with join or cancel
Channel<T>Bounded FIFO async communication channel

Function parameters and returns use explicit types in most examples:

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

Float crosses the native boundary as C double. Arithmetic and ordering require matching numeric types; use Int.toFloat() and Float.toInt() for explicit conversion. Float.toInt() truncates toward zero and Float.toString() uses a locale-independent representation.

aura
val ratio: Float = 3.0 / 2.0
val whole: Int = ratio.toInt()
val optional: Float? = null

String helpers (alpha + C12)

FormNotes
s.lenByte length (field)
s.isEmpty()len == 0
s.charAt(i)Byte as Int; OOB throws
s + t / "hi ${name}"Concat / interp (idents)
s.startsWith / contains / endsWithSearch
s.indexOf(sub)Byte index; −1 if missing; empty sub → 0 (C12f)
s.split(sep)Array<String>; empty sep throws; consecutive seps → empty segments (C12g)
s.trim() / trimStart / trimEndASCII whitespace MVP; owned copy (C12h)
s.toInt()Int?; full-string decimal; no auto-trim; bad/overflow → null (C12i)
s.substring(start, end)Exclusive end; byte indices (C11d)

Indices are UTF-8 bytes, not Unicode scalar values. No embedded NUL.

Non-null by default

  • T means must be present — no implicit null.
  • T? is the opt-in nullable form.
aura
fun greet(name: String) {
  println(name)
}

fun maybeGreet(name: String?) {
  // name may be absent
}

This is a core product rule from RFC-000 / RFC-002: safety by default, escape hatches explicit.

Flow narrowing

After a null check, the compiler treats the value as non-null on that path:

aura
fun lenOrZero(s: String?): Int {
  if (s != null) {
    return s.len
  }
  return 0
}

Force-unwrap

!! asserts non-null. Prefer narrowing when you can; use !! when you have an invariant the type system does not see yet.

aura
fun mustHave(s: String?): Int {
  return s!!.len
}

Misuse can fail at runtime — treat it as an explicit escape hatch.

Null coalesce and safe call

?: provides a default when the left side is null:

aura
fun label(name: String?): String {
  return name ?: "anonymous"
}

?. is safe call on a nullable receiver (result is nullable):

aura
class Greeter(val name: String) {
  fun greet(): String {
    return this.name
  }
}

fun demo(g: Greeter?): String? {
  return g?.greet()
}

Corpus: types/coalesce.aura, class/safe_call.aura.

is type test

aura
if (value is Greeter) {
  // value matches class / interface
}

See Classes, structs & interfaces and corpus/iface/is_test.aura.

Type aliases and const

aura
type Id = Int
const MAX: Int = 100

Scoped references

ref T is a non-owning, non-null reference with lexical lifetime. It cannot be returned, stored in a heap object, captured by an escaping lambda, or moved across await, spawn, task storage, or channel boundaries. Use an owning value or clone() when the value must outlive its source scope.

aura
fun firstLength(items: Array<Int>): Int {
  val view: ref Array<Int> = items
  return view.len
}

Generics (preview)

Type parameters monomorphize for concrete uses:

aura
class Box<T>(var value: T) {}

fun id<T>(x: T): T {
  return x
}

Bounds (T : Named, where) are part of the type system — see RFC-002 and corpus generics samples. Generic interface implements: Classes.

Next

All docs pages