Skip to main content

Conditional expressions

Both if and when can be used as expressions, producing a value instead of branching over statements. For their statement forms, see Conditional statements.

val a = 7;
val b = 3;
val n = 2;

val max = if (a >= b) a else b;
print(max); // 7

val size = when (n) {
0 -> 'zero';
1, 2 -> 'small';
else -> 'big';
};
print(size); // small

An if expression always needs an else branch, and a when expression must be exhaustive; an else case makes it exhaustive. Only the chosen arm evaluates. In an at-expression, a when expression is translated to the SQL CASE WHEN ... THEN expression.

Value block arms​

An arm can be a value block instead of a plain expression: zero or more statements followed by a trailing expression without a semicolon, which is the block's result.

function compute() = 21;

val cond = true;
val fallback = 0;
val n = 2;

val x = if (cond) {
val v = compute();
v * 2
} else fallback;
print(x); // 42

val y = when (n) {
0 -> 'zero';
1, 2 -> {
val s = 'small';
s + ':' + n
}
else -> 'big'
};
print(y); // small:2

A block arm has plain code-block semantics; it runs inline, in the enclosing function's frame:

  • Enclosing local variables are visible and assignable, and nullability analysis flows through the block.

  • return returns from the enclosing function. An arm that returns on all paths yields no value, and the conditional takes its result type from the other arms:

    val sign = if (n < 0) { return 'negative'; } else { 'non-negative' };
  • break and continue inside a block arm bind to the enclosing loop.

  • At-expression scope applies: attributes and the $ placeholder resolve inside a block arm of a collection-at projection.

The trailing expression without a semicolon is the block's value. A block with statements only is unit-typed, which a conditional arm can't be, unless it always returns.

Semicolons in a when expression are unchanged for expression arms: an expression arm is terminated by ;, and the last case may omit it. A block arm ends at its closing } and takes no ;, like a block in a when statement.

Restrictions​

  • In expression positions with no enclosing body statement, that is, an at-expression body or a parameter or attribute default value, return, break, and continue can't escape the block. The block itself is fine.
  • A value block can't be used in a global constant's expression, because its statements can't be validated as constant.

The same value-block form is available as a lambda body.

note

Value block arms are available from Rell 0.16.1.