const value = if (a) {
return true
} else {
return switch (b) {
case 1: return false
default: return undefined
}
} const value = if (a) {
return true
} else {
return switch (b) {
case 1: return false
default: return undefined
}
} value := (if a then True
else (
case b is
when 1 => False,
when others => Undefined
));https://learn.microsoft.com/en-us/dotnet/csharp/language-ref...
In a typical programming language we can write something like x = 5; assigning 5 to the variable x. That 5 there is an expression, we can write x = (3 * 2) - 1; with the same effect, that's a more complicated expression. We can call a function here: x = f(3); or if our language has methods we can even call those: x = some.function(parameters);
In Rust I can write x = if it.should_be_nine() { 9 } else { 5 }; // because if is an expression
Since Rust's loops are also expressions, x = loop { let stuff = get_stuff(); if stuff.is_good() { break stuff } }; // ... once the stuff is good, break out of the loop and we'll assign that stuff to x
My informal understanding of a predicate may need refining.
It might be you've just always used languages where you can do this, or that you assumed you can but actually you never tried in a language you use.
In C for example we can't write this:
int x = if (1 == 2) { 3 } else { 4 }; // Not valid C syntax
C provides a special operator, the only one in the language which has three operands and thus it's often just called "the ternary operator" although other ternary operators can technically exist, to achieve the same thing: int x = (1 == 2) ? 3 : 4; // Valid C syntax using ternary operator
But, how about this? int x = switch 3 { case 1: 4; case 2: 8; default: 0; }; // Can't do this either
There's no way to express that in C or C++ today. The closest is the "Immediately Invoked Lambda" from C++ which is illustrated nearby in this thread. Barry Revzin apparently proposed a way to do this in C++ 26 because C++ wants to have pattern matching and pattern matching kinda sucks without this feature. const value = [&]() {
if (a) {
return true;
}
return switch (b) {
case 1: return false;
default: return undefinied;
}
}(); let value = if a { true } else { match b { 1 => false, _ => undefined } };
And notice that because now we're a function our relationship to the world changed, how does your immediately invoked lambda do this? let value = if a { true } else { match b { 1 => false, 2 => return foo, _ => undefined }};
With expression syntax returning from the function we're in is fine† but in your lambda you can't do that, you need control flow logic outside the lambda to handle it.† You might wonder about the inferred type of this expression since it might return. The type of the return expression in Rust is ! aka Never, which is an empty type. In the same way that N + 0 == N in integer arithmetic, any type plus an empty type is the original type again in type arithmetic, so the type of the expression isn't altered.
Still the syntax is a bit confusing. In ML languages (f# and also rust are somehow descendants of ML) you can just use if .. else if .. else expressions. They work like ternaries! But easier readable. Nested ternaries are useful, but get really hard to read very fast. (x = condition1 ? A : condition2 ? B : C;)
LLVM and GCC can at least.
const value = (()=>{
…
})()