Type System
StarLang is a statically typed language. All variables, parameters, and return values require type annotations.
Primitive Types
| Type | Description | Example |
|---|---|---|
nil |
Null value | nil |
bool |
Boolean | true, false |
number |
64-bit double | 3.14, -1.5 |
i32 |
32-bit signed integer | 42, -10 |
u8 |
8-bit unsigned integer | 0..255 |
string |
UTF-8 text | "hello" |
array |
Dynamic array (untyped) | [1, "a", true] |
dict |
Key-value map (untyped) | {"port": 8080} |
function |
Function reference | fn add(a:i32, b:i32):i32 |
struct |
User-defined composite type | struct Point { x:number, y:number } |
chan |
Channel for task communication | chan(4), chan(0) |
value |
Dynamic type — holds any value, narrowed on read | queue.pop(q) |
result<T> |
Error result from try |
result<number>, result<string> |
void |
For functions that return nothing | only used as return type |
value (dynamic type)
value holds any StarLang value regardless of its concrete type. It is used where a container must accept heterogeneous payloads — most notably queue, whose items are typed value.
Assigning a value to a concrete type performs checked narrowing: the runtime verifies the actual type matches the target and raises a type fault (code 2) on mismatch, catchable with try.
var q: i32 = queue.new(8)
queue.push(q, 42)
var n: number = queue.pop(q) # checked narrow value -> number
String Escape Sequences
String literals support the following escape sequences:
| Escape | Character |
|---|---|
\n |
Newline (0x0A) |
\t |
Tab (0x09) |
\r |
Carriage return (0x0D) |
\\ |
Backslash |
\" |
Double quote |
\0 |
Null byte |
var line: string = "hello\tworld\n"
var path: string = "C:\\Users\\star"
var quote: string = "she said \"hi\""
Numeric Literals
Integer literals (no decimal point) are number by default. When assigned to an i32 or u8 variable or passed to a function expecting an integer type, the compiler auto-converts them:
var x:i32 = 42 # 42 is number literal, auto-converted to i32
var y:number = 42 # 42 stays as number — both work
var f:number = 3.14 # only number, cannot be i32
Integer Types
StarLang supports two integer types alongside number:
var x:i32 = 42 # 32-bit signed integer
var b:u8 = 200 # 8-bit unsigned (0-255)
var f:number = 3.14 # 64-bit floating point
Integer arithmetic uses dedicated opcodes and does not lose precision to floating point.
Arithmetic
var a:i32 = 10
var b:i32 = 3
var sum:i32 = a + b # 13
var diff:i32 = a - b # 7
var prod:i32 = a * b # 30
var quot:i32 = a / b # 3 (integer division)
var rem:i32 = a % b # 1
var neg:i32 = -a # -10
Integer Division
Integer division truncates toward zero (same as C):
-7 / 2 = -3 (truncation toward zero), not -4 (floor division as in Python).
u8 Promotion
u8 values are promoted to i32 for all arithmetic operations:
u8 Overflow
Casting to u8 wraps modulo 256 (same as C uint8_t cast):
No runtime error is raised — this is a silent wrap. If you need range checking, validate before casting.
No Implicit Integer/Float Mixing
Arithmetic between integers and floats is a compile error:
Use explicit type casts instead (see below).
Comparison Auto-Coercion
Comparisons between integers and numbers are allowed — the compiler inserts implicit conversion:
var x:i32 = 42
assert(x == 42, "works") # number literal auto-converted to i32
assert(x > 10, "works") # number literal auto-converted to i32
Type Casting
Explicit casts between numeric types:
var x:i32 = 42
var f:number = number(x) # i32 -> number: 42.0
var pi:number = 3.14
var n:i32 = i32(pi) # number -> i32: 3 (truncates toward zero)
var b:u8 = u8(x) # i32 -> u8: 42
var w:i32 = i32(b) # u8 -> i32: 42
Generic Types
Arrays and dicts can be parameterized with element types:
Typed Arrays
var nums:array<i32> = [10, 20, 30]
var names:array<string> = ["alice", "bob"]
var flags:array<bool> = [true, false, true]
Generic type parameters are enforced at both compile time and runtime. The compiler checks element types during subscript assignment and inserts implicit numeric conversions where applicable. The VM provides a runtime safety net — assigning a wrong-typed value raises an error catchable with try.
Subscript Assignment
Array and dict elements can be assigned via subscript notation:
var nums:array<i32> = [10, 20, 30]
nums[0] = i32(99) # OK: i32 matches
nums[1] = 42 # OK: number literal auto-converted to i32
var cfg:dict<string, i32> = {"port": 8080}
cfg["port"] = i32(9090) # OK: updates existing key
cfg["timeout"] = 30 # OK: inserts new key
var names:array<string> = ["alice", "bob"]
names[0] = "charlie" # OK: string matches
Type mismatches produce compile-time errors when the element type is known:
Numeric auto-coercion rules apply:
array<i32>accepts number literals (auto-converted to i32)array<number>accepts i32/u8 values (auto-converted to number)array<u8>accepts i32 values (truncated to u8)
Typed Dicts
var config:dict<string, i32> = {"port": 8080, "timeout": 30}
var lookup:dict<string, string> = {"name": "star", "version": "0.2"}
Untyped Collections
Omitting the type parameter gives a mixed-type collection:
Type Annotations
Variables use : to specify the type:
var x:i32 = 42
var name:string = "stardyn"
var active:bool = true
var items:array<number> = [1.5, 2.7, 3.9]
var config:dict<string, i32> = {"port": 8080}
Type Checking
Type mismatch produces a compile-time error:
var x:number = "hello" # ERROR: expected number, got string
var y:string = 42 # ERROR: expected string, got number
Missing type annotation is a compile error:
void vs nil
| Type | Usage | In variables | As return type |
|---|---|---|---|
void |
Non-returning fn | No | Yes |
nil |
Null value | Yes | Yes |
Result Type
The try keyword returns a type-safe result<T> value. The inner type T matches the return type of the called function.
fn divide(a:number, b:number):number {
if (b == 0) { raise "division by zero" }
return a / b
}
var res:result<number> = try divide(10, 0)
assert(res.failed == true)
assert(res.error == "division by zero")
Fields: .failed (bool), .code (i32), .error (string), .value (T). See Error Handling for details.
Bytecode Type Tags
Each value is stored in memory with a 1-byte type tag:
| Tag | Hex | Type |
|---|---|---|
| NIL | 0x00 | nil |
| BOOL | 0x01 | bool |
| NUMBER | 0x02 | number |
| STRING | 0x03 | string |
| ARRAY | 0x04 | array |
| DICT | 0x05 | dict |
| FUNCTION | 0x06 | function |
| I32 | 0x07 | i32 |
| U8 | 0x08 | u8 |
| STRUCT | 0x09 | struct |
| CHANNEL | 0x0A | chan |
| RESULT | 0x0B | result<T> |