Step 1. Variables and types
Why#
Most bugs in programs are values that changed in the wrong place at the wrong time. That is why a binding in OxL is
immutable by default: let creates a name that cannot be reassigned. If a value must change, you say so with var, and the
reader of the code immediately sees which variables are "alive".
Types are static, but you rarely write them: the compiler infers the type from the value. You write types in function signatures and where a value is not obvious (§3).
Example#
fn main() io {
let name = "Ann" // let is an immutable binding; the type str is inferred
var visits = 0 // var is a mutable variable
visits += 1
visits += 1
let ratio: f64 = 2.5 // the type may be written explicitly
let big = 1_000_000_i64 // suffix and separators in numbers
let letter = 'x'
let ok = visits == 2 && !name.isEmpty()
print("{name} visited {visits} times, ratio {ratio}, big {big}") // {…} inside a string is interpolation
print("{letter} {ok} {name.len()} {name.upper()}")
let (a, b) = (10, 3) // a tuple and destructuring
print("{a / b} {a % b} {a as f64 / b as f64}")
let nothing: i32? = none // i32? is "a value or none"
print("{nothing ?? 42}") // ?? supplies a default
}Ann visited 2 times, ratio 2.5, big 1000000 x true 3 ANN 3 1 3.3333333333333335 42
Walkthrough#
let name = "Ann"- an immutable binding of typestr. Strings are UTF-8 text; copying them is cheap.var visits = 0- a mutable variable of an integer type (the type is inferred).+=,-=and friends requirevar.1_000_000_i64- the_separator for readability and a type suffix. The main numeric types arei8…i128,u8…u128,usize,f32,f64. Arithmetic checks overflow:+,-,*panic when the range is exceeded instead of silently wrapping (the explicit variants are+%wrapping and+|saturating, §3.1)."{name} visited {visits} times"- any expression can be put in curly braces inside a string.(a, b)is a tuple;let (a, b) = …takes it apart.10 / 3is integer division, so for a real result the numbers are converted withas f64.i32?means "i32ornone".noneis the only way to say "no value": the language has nonull.a ?? btakesaif it is present, otherwiseb.
Common mistake: changing a let#
If you try to change an immutable binding, the compiler stops the build and suggests var:
fn main() {
let count = 0
count += 1 // let is immutable
}mutate-immutable
Diagnostic: mutate-immutable. The fix is to declare var count = 0.
The second frequent mistake is a type mismatch. OxL does not convert types silently: a string does not go into an i32, and an i32
does not go into an i64 without an explicit as:
fn main() {
let count: i32 = "five"
}type-mismatch
Diagnostic: type-mismatch. A typo in a name - unresolved-name - is also caught at compile time:
fn main() {
let total = 10
print(totl)
}unresolved-name
Remember#
letby default;varonly where the value really changes.- Numbers and strings are never converted into each other implicitly.
- The absence of a value is the type
T?, not a specialnull; the compiler makes you handlenone.
Next: functions.