Normative rules: RFC-002. MVP keywords and surface: RFC-001 §6.0.
Scalars you will see first
| Type | Notes |
|---|---|
Int | Integer (overflow policy is documented in RFCs; prefer checked ops in dev) |
Float | IEEE-754 double; NaN and infinities follow the host C double rules |
Bool | true / false |
String | Immutable 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:
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.
val ratio: Float = 3.0 / 2.0
val whole: Int = ratio.toInt()
val optional: Float? = nullString helpers (alpha + C12)
| Form | Notes |
|---|---|
s.len | Byte length (field) |
s.isEmpty() | len == 0 |
s.charAt(i) | Byte as Int; OOB throws |
s + t / "hi ${name}" | Concat / interp (idents) |
s.startsWith / contains / endsWith | Search |
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 / trimEnd | ASCII 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
Tmeans must be present — no implicit null.T?is the opt-in nullable form.
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:
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.
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:
fun label(name: String?): String {
return name ?: "anonymous"
}?. is safe call on a nullable receiver (result is nullable):
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
if (value is Greeter) {
// value matches class / interface
}See Classes, structs & interfaces and corpus/iface/is_test.aura.
Type aliases and const
type Id = Int
const MAX: Int = 100Scoped 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.
fun firstLength(items: Array<Int>): Int {
val view: ref Array<Int> = items
return view.len
}Generics (preview)
Type parameters monomorphize for concrete uses:
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.