LEVIATHAN v962456e · 962456eee1

Expressions

Primary expressions

Literals, names, this, parentheses, array and range literals, lambdas and string interpolation, the building blocks of every other expression.

since 0.1.0-alpha.1linuxwindowswasm

Description

A primary expression is the smallest unit an operator or a call can act on:

form meaning
42 3.14 "s" true false a literal
name a local variable, a parameter, a member, a function or a type
this the enclosing instance, or the receiver value inside a method of a primitive type
(expr) grouping
[e1, e2, ...] an array literal; a range inside the brackets is spread into its elements
a .. b a range value, both endpoints included
(p1, p2) => expr a lambda; its parameters are written without types and it captures the variables it uses
await expr a suspension point that parks the current task until expr completes
inject Type an explicit injection selector for Type

Literals, grouping, arrays, ranges and lambdas

class Sink {
    int total = 0;
    Sink (<<)(int n) {
        total = total + n;
        return this;
    }
}

void apply((int) => void f) {
    f(5);
}

void main() {
    int x = 5;
    console.writeln((x + 1) * 2);

    Array<int> listed = [10, 20, 30];
    Array<int> spread = [1..4];
    console.writeln(listed);
    console.writeln(spread);

    var inc = (n) => n + 1;
    console.writeln(inc(4));

    var sum = (p, q) => {
        int t = p + q;
        return t * 2;
    };
    console.writeln(sum(1, 2));

    Sink sink = Sink();
    apply((n) => sink << n);
    console.writeln(sink.total);
}
main();
12
[10, 20, 30]
[1, 2, 3, 4]
5
6
5

Rules

  • A lambda body is either an expression ((x) => x + 1) or a statement block ((x) => { ...; return y; }).
  • An expression body in a position where the lambda must return void is treated as a statement: its value is discarded, exactly like an expression statement. That is why apply((n) => sink << n) is legal even though << returns its receiver. A block body that returns a value where void is expected is still an error, and a lambda whose expected return type is not void has its body checked against that type.
  • A lambda captures a primitive local variable (int, float, bool, string) by snapshot: a later change to the variable is not seen by the lambda, and a change the lambda makes to its own copy is not seen outside. To share mutable state, capture an object and change its fields.
  • this is available only inside a class body; using it elsewhere is a compile error.
  • A range a .. b includes both endpoints. Inside array brackets the range is spread: [1..4] is [1, 2, 3, 4].
  • Several keywords (get, set, is, in and others) may be used as member names after . or :: and as method names after a return type. They are keywords only at the start of a statement or declaration.

String interpolation

"...${expr}..." inserts the text of expr into the string. It works in both quote styles and is shorthand for concatenating the string pieces with the toString() of each hole, so a hole may contain any expression whose type has a toString().

  • \${ writes a literal ${.
  • A lone $ that is not followed by { is an ordinary character.
  • An empty hole (${}) and an unterminated hole are compile errors.
  • A string literal inside a hole must use the opposite quote style from the string that contains it: "${'has a } in it'}" is valid, while a nested literal with the same quote character ends the outer string at that point.

Interpolation

int x = 5;
console.writeln("x=${x}, next=${x + 1}");
console.writeln("literal \${x} and a $ sign");
console.writeln("${'has a } in it'}");
console.writeln('${"double quotes inside"}');
x=5, next=6
literal ${x} and a $ sign
has a } in it
double quotes inside

Examples

A lambda captures primitives by snapshot and objects by reference

class Box {
    int n = 0;
}

void main() {
    int seen = 0;
    var bump = () => { seen = seen + 1; };
    bump();
    bump();
    console.writeln(seen);

    Box box = Box();
    var inc = () => { box.n = box.n + 1; };
    inc();
    inc();
    console.writeln(box.n);

    int base = 10;
    var add = (x) => x + base;
    base = 100;
    console.writeln(add(1));
}
main();
0
2
11

Keywords as member names

class Gate {
    int in = 3;
    bool is() => true;
    int get() => 7;
}

Gate g = Gate();
console.writeln(g.in);
console.writeln(g.is());
console.writeln(g.get());
3
true
7

Notes

  • A variable that holds a function value, such as var inc = (n) => n + 1;, is called with inc(4) inside a function body. Declare such variables inside a function.
  • var and let declarations, which infer the type from the initializer, are accepted inside function bodies and inside the body of a control statement. At the outermost level of a script, write the declared type instead.
  • await and inject are covered with the features they belong to (tasks and dependency injection).

See also

  • Array — An ordered sequence of values of one type, Array<T>, with value semantics.
  • string — An immutable sequence of text, stored as UTF-8.