Type System
ScarScript is statically typed with full compile-time inference. Every expression has a known type before the program runs.
Primitive Types
| Type | Go Backing | Literals | Example |
|---|---|---|---|
int | int | 42, 0, -7 | val n = 42 |
dec | float64 | 3.14, 0.5 | val pi = 3.14 |
str | string | "hello" | val s = "hi" |
bool | bool | true, false | val ok = true |
void | — | no literal | functions with no return |
int
Signed 64-bit integer. Supports arithmetic, comparison, and modulo.
val count = 42
val sum = 10 + 32 // 42
val half = 42 / 2 // 21 (integer division)
dec (decimal)
64-bit floating point. Use for prices, measurements, and any fractional value.
val price = 99.99
val rate = 0.05
val pi = 3.14159
// Int literals widen to dec automatically
val x: dec = 4 // 4.0
val y = 1 + 2.5 // 3.5
dec, not float. The lexer tokenizes 1..5 as a range (1 .. 5), so decimals always require a single dot: 1.5.str
Immutable UTF-8 string with built-in methods.
val name = "Zawiyar"
val greeting = "Hello, {name}!"
name.len() // 7
name.upper() // "ZAWIYAR"
name.lower() // "zawiyar"
name.contains("awi") // true
bool
Two values: true and false. Produced by comparisons and logical operators.
val adult = age >= 18
val ok = a == b and c != d
val off = not enabled
Type Inference
Annotations are optional. The checker infers the type from the right-hand side:
val a = 42 // inferred int
val b = 3.14 // inferred dec
val c = "hi" // inferred str
val d = true // inferred bool
val e = [1, 2, 3] // inferred array of int
// Explicit annotation still works and is checked
val f: str = 42 // ERROR: expected str, got int
cannot infer type and asks for an annotation.Tuples & Multiple Returns
Functions can return multiple values as a tuple. Destructure at the call site:
func divide(a: int, b: int) (int, bool) {
if b == 0 { return 0, false }
return a / b, true
}
val result, ok = divide(10, 2) // result=5, ok=true
// Or with explicit types
val q: int, ok: bool = divide(10, 0)
You can also destructure multiple declarations in one statement:
val a, b = 1, 2
Arrays
Homogeneous collections. The element type is inferred from the first element.
val nums = [1, 2, 3] // []int
val names = ["a", "b"] // []str
val mixed = [1, "a"] // ERROR: heterogeneous array
nums.len() // 3
nums[0] // 1
Nullable / Optional
Variables can be declared without a value. The or operator provides the fallback:
val config: str = sys.env("CONFIG") or "default"
val status = data.status or "unknown"
Static Checking Rules
The type checker enforces these rules at compile time. The first error aborts compilation.
Assignment compatibility
val x: str = 42
// error: expected str, got int (line 1, col 11)
Argument checking
math.abs(3.14)
// error: argument 1 expects int, got dec
Missing return
func f() int {
if true { return 1 }
// error: missing return
}
Unreachable code
return 1
print("never")
// error: unreachable code
Arithmetic type mismatch
val s = 1 + "a"
// error: cannot add int and str
file:line:col: error: message — compatible with most editors' error parsers.