4 Expression forms
4.1 Variable expressions
expr
var_name
The value of a variable, which must be a function parameter, bound with let, or defined with def. For example,
let x = 5 println('%p', x)
prints “5”.
Lexically, a variable is a letter or underscore, followed by zero or more letters, underscores, or digits, optionally ending in a question mark or exclamation point.
4.2 Literal expressions
expr
number
A numeric literal.
expr
string
A string literal.
expr
The true Boolean value.
expr
The false Boolean value.
This is one of only two values that are not considered truthy for the purpose of conditionals. The other non-truthy value is None.
expr
A special value for representing missing data. This is also the result of functions that are called just for their side effects, such as print.
This is one of only two values that are not considered truthy for the purpose of conditionals. The other non-truthy value is False.
4.3 Functions and application expressions
expr
Evaluates all the expressions; ⟨expr0⟩ must evaluate to a procedure. Then applies the result of ⟨expr0⟩ with the results of the other expressions as arguments.
For example,
fact(5)
calls the function fact with argument 5, and
ack(5 + 1, 5 + 2)
calls the function ack with arguments 6 and 7.
Note that method calls are just object method lookup combined with procedure applcation. That is, when you write
q.enqueue(5)
that means lookup the enqueue method in q, and then apply the result to 5.
expr
λ var_name1, ..., var_namek: ⟨simple⟩
Creates an anonymous function with parameters var_name1, ..., var_namek and body ⟨simple⟩. For example, the function to add twice its first argument to its second argument can be written
lambda x, y: 2 * x + y
4.4 Vectors and indexing expressions
expr
Expression ⟨expr1⟩ must evaluate to a vector or string o; ⟨expr2⟩ must evaluate to an integer n between 0 and o.len() - 1. Then this returns the nth element of vector o or the nth character of string o.
expr
Creates a new vector of length k whose values are the values of the expressions.
For example:
let v = [ 1, 2, 3, 4, 5 ]
expr
Constructs a new vector whose length is the value of ⟨exprsize⟩, filled with the value of ⟨exprinit⟩. That is,
[ 0; 5 ]
means the same thing as
[ 0, 0, 0, 0, 0 ]
Note that ⟨exprinit⟩ is not re-evaluated to produce each element, so an expression like [[0; 5]; 5] produces a vector that contains the same vector five times, not five different subvectors.
expr
Vector comprehensions: produces a vector of the values of ⟨exprelem⟩ while iterating the variable(s) over ⟨expriter⟩. In particular, ⟨expriter⟩ must be a vector v, a string s, or a natural number n; in which case the iterated-over values are the elements of v, the characters of s, or counting from 0 to n - 1, respectively. If one variable var_name is provided, it takes on those values. If two are provided, then var_name2 takes on those values, while var_name1 takes on the indices counting from 0 upward.
For example,
[ 10 * n for n in [ 5, 4, 3, 2, 1 ] ]
evaluates to
[ 50, 40, 30, 20, 10 ]
And
[ 10 * n + i for i, n in [ 5, 4, 3, 2, 1 ] ]
evaluates to
[ 50, 41, 32, 23, 14 ]
expr
[ ⟨exprelem⟩ for var_name1, var_name2 in ⟨expriter⟩ if ⟨exprcond⟩ ]
If the optional ⟨exprcond⟩ is provided, only elements for which ⟨exprcond⟩ is non-false are included. That is, the variable(s) take on each of their values, then ⟨exprcond⟩ is evaluated in the scope of the variable(s). If it’s non-false then ⟨exprelem⟩ is evaluated and included in the resulting vector.
For example,
[ 10 * n for n in [ 5, 4, 3, 2, 1 ] if odd?(n) ]
evaluates to
[ 50, 30, 10 ]
4.5 Structs and projection expressions
expr
⟨expr⟩.prop_name
Expression ⟨expr⟩ must evaluate to struct value that has field prop_name or an object value that has method prop_name; then this expression evaluates to the value of that field of the struct or that method of the object.
expr
struct_name { field_name1: ⟨expr1⟩, ..., field_namek: ⟨exprk⟩ }
Constructs a struct with the given name and the values of the given expressions for its fields. The struct must have been declared with those fields using struct.
If a variable with the same name as a field is in scope, omitting the field value will use that variable:
struct Foo: let bar let baz let bar = 4 let baz = 5 assert Foo { bar, baz: 9 } == Foo(4, 9)
4.6 Operator expressions
Operators are described in order from tighest to loosest precedence.
expr
Raises the value of ⟨expr1⟩ to the power of the value of ⟨expr2⟩, both of which must be numbers.
The ** operator is right-associative.
expr
-⟨expr⟩
+⟨expr⟩
Logical negation, bitwise negation, numerical negation, and numerical identity.
not ⟨expr⟩ evaluates ⟨expr⟩, then returns True if the result was False or None, and False for any other result.
~⟨expr⟩ requires that ⟨expr⟩ evalutes to an integer or Boolean; it flips every bit of the number, or negates the Boolean.
-⟨expr⟩ and +⟨expr⟩ require that ⟨expr⟩ evaluates to a number. Then - negates the number, and + returns it unchanged.
expr
Multiplies, divides, or modulos the values of the expressions, respectively.
expr
Addition:
Given two numbers, adds them.
Given two strings, concatenates them.
Given a string and another value, in any order, converts the other value to a string and concatenates them.
Anything else is an error.
expr
Subtracts two numbers.
expr
Left and right bitwise shift.
expr
Bitwise and for integers; logical and for Booleans.
expr
Bitwise xor for integers; logical xor for Booleans.
expr
Bitwise or for integers; logical or for Booleans. (Not written with the backslash.)
expr
Operator == is structural equality (except for classes that override it), and != is its negation. Operator is is physical equality, and |is not| (not written with the vertical bars) is its negation. To understand the difference, suppose that we create two different vectors with the same contents. Those vectors are structurally equal but not physically equal.
Operators <, <=, >, and >= are the standard inequalities for numbers and characters, and compare strings in lexicographic order.
expr
Short-circuiting logical and. First evaluates ⟨expr1⟩; if the result is False or None then the whole conjunction is False; otherwise, the result of the conjunction is the result of ⟨expr2⟩.
expr
Short-circuiting logical or. First evaluates ⟨expr1⟩; if the result is non-false then the whole disjunction has that result; otherwise the result of the disjunction is the result of ⟨expr2⟩.
expr
The ternary expression first evaluates the condition ⟨exprcond⟩. If non-false, evaluates ⟨exprthen⟩ for its value; otherwise, evaluates ⟨exprelse⟩ for its value.
For example:
def parent(link): link.parent if rbn?(link) else None