Reference / Expressions
Expressions
An expression is code that the program calculates: a literal, a name, an operation, a call, or a block, if, match or loop. Most expressions give a value.
fn square(n: i64) -> i64 {
return n * n
}
fn main() {
let n = 4
let size = if n > 3 { "large" } else { "small" }
print(square(n) + 1) // 17
print(size) // large
}
Order of evaluation
The program calculates the parts of an expression from left to right, then uses them. Precedence decides how the parts group, not when they run. These are the parts:
- the operands of an operator
- the arguments of a call
- the receiver of a method, before its arguments
- the elements of an array literal
- the parts of an interpolation
fn show(n: i64) -> i64 {
print("part {n}")
return n
}
fn add(a: i64, b: i64) -> i64 {
return a + b
}
fn main() {
print(show(1) + show(2) * show(3))
print(add(show(4), show(5)))
}
part 1 part 2 part 3 7 part 4 part 5 9
The program calculates each part once. &&, ||, ??, ?. and a comparison chain can skip a part (Logical operators, Default values, Optional chaining, Comparison chains).
Names and parentheses
A name reads the value of a binding or a constant. A name that is not in scope is an error (E0033).
Parentheses group an expression. They do not change its value or its type.
fn main() {
let n = 6
print((n + 1) * 6) // 42
}
Blocks
A block is a list of statements between { and }. When its last statement is an expression, that expression is the value of the block.
fn main() {
let area = {
let width = 6
let height = 7
width * height
}
print(area) // 42
}
The rules:
- A name that a statement in the block declares is in scope only to the end of the block.
- A block that does not end in an expression has no value (E0043).
- A block that reaches a
return,breakorcontinuehas the typenever(Types). - A statement cannot start with
{(E0081).
fn main() {
{ // error[E0081]
print(1)
}
}
E0081: what this error means
if
An if with an else is an expression. Its value is the value of the branch that runs.
fn main() {
let n = 7
let kind = if n % 2 == 0 { "even" } else { "odd" }
print(kind) // odd
let size = if n < 5 { 1 } else if n < 10 { 2 } else { 3 }
print(size) // 2
}
The rules:
- The condition must be a
bool(E0032). - The values of the branches must have one type (E0032). When one branch is a
Tand another aT?, theifis aT?. A branch of the typenevertakes the type of the others (Types). - An
ifwithout anelsehas no value (E0043). It is a statement. - An
else ifis anifin theelsebranch.
fn main() {
let n = 7
let kind = if n > 5 { "big" } else { 0 } // error[E0032]
}
E0032: what this error means
match
A match is an expression. Its value is the value of the arm that matches. The values of the arms follow the rules of the branches of an if. Enums and patterns tells the patterns, the guards and the coverage rules.
fn main() {
let n = 3
let name = match n {
1 => "one"
2 | 3 => "a few"
_ => "many"
}
print(name) // a few
}
loop
A loop is an expression. break with a value ends the loop, and that value is the value of the loop. Statements tells how a loop runs, and how a loop label names it.
fn main() {
let mut n = 1
let first = loop {
n = n * 3
if n > 20 {
break n
}
}
print(first) // 27
}
The rules:
- The values of all the
breaks of a loop must have one type (E0032). - A
breakvalue of the typenevertakes the type of the otherbreakvalues, as a branch of anifdoes. - The loop has the type
neveronly when it has nobreak, or when eachbreakhas a value of the typenever(Types). - A loop whose
breaks have no value has no value (E0043). This applies also when the otherbreaks have values of the typenever. - A loop that has a
breakwith no value and abreakwith a value is an error (E0043).
fn wait(ready: bool) {
loop {
if ready {
break
}
break panic("not ready")
}
print("finished")
}
fn main() {
wait(true) // finished
}
Calls
A call f(a, b) runs the function f with the arguments a and b. Its value is the value that the function returns.
fn area(width: i64, height: i64) -> i64 {
return width * height
}
fn main() {
print(area(6, 7)) // 42
}
The rules:
- The number of arguments must be the number of parameters (E0053).
- Each argument must have the type of its parameter (E0032). Where the parameter is a
T?, aTbecomes aT?(Types). - A call of a function that does not exist is an error (E0052).
- A call of a function that has no return type has no value (E0043).
- A call written with the name of a type, such as
f64(n), is a conversion (Types).
fn area(width: i64, height: i64) -> i64 {
return width * height
}
fn main() {
print(area(6)) // error[E0053]
}
E0053: what this error means
Method calls
A method call x.m(a) runs the method m of the value x, with x as its receiver (Classes). The built-in types have methods too, such as the methods on numbers (Types).
fn main() {
let x = 2.0
print(x.sqrt()) // 1.4142135623730951
print(7.min(3)) // 3
}
A name that is not a field or a method of the type is an error (E0063). A field called as a method is an error too (E0058).
A method of a class or an enum read as a field is an error (E0057), and so is len of an array. Another built-in method read as a field, such as s.len on a string, is E0063.
Fields
x.name reads the field name of the object x (Classes). For an optional object, use ?. (Operators).
class Point {
x: i64
y: i64
}
fn main() {
let p = Point(x: 3, y: 4)
print(p.x + p.y) // 7
}
Indexes
xs[i] reads the element at the index i of the array xs (Arrays). The first element has the index 0. The index must be an i64 (E0032).
fn main() {
let xs = [10, 20, 30]
print(xs[0]) // 10
print(xs[2]) // 30
}
An index that is negative, or not less than the length of the array, stops the program with a panic.
fn main() {
let xs = [10, 20, 30]
print(xs[3])
}
sisu: panic at example.sisu:3:14: index 3 out of bounds for length 3
Only an array has an index. An index on another value, such as a string, is an error (E0068).
Expressions as statements
An expression can stand as a statement, such as a call of print. When its value is not used, and it is not a call that returns no value, the program builds with a warning (W0004).
fn main() {
let n = 2
n * 21 // warning[W0004]
print(n) // 2
}
W0004: what this warning means
An expression that has no value cannot be used as a value: as the value of a let, an argument or an operand (E0043). These expressions have no value:
- a call of a function that has no return type, such as
print(1) - an
ifwithout anelse - a block that does not end in an expression
- a
loopwhosebreaks have no value - an expression of the type
never(Types)
fn main() {
let x = print(1) // error[E0043]
}
E0043: what this error means
Sisu