let name = match color_code {
0 => "red",
1 => "blue",
2 => "green",
_ => "unknown",
};
The RHS of the `=>` has to be an expression, since we're assigning it to a variable. Here, you should already see one "useful" side-effect of what you're calling "syntactic elements" (I'd perhaps call them "block statements", which I think is closer to the spirit of what you're saying.) The whole `match … {}` in the example above here is an expression (we assign the evaluation of it to a variable).
> What practical value is it to users to allow "return <expr>" to itself be an expression?
Now, what if I need to return an error?
let name = match color_code {
0 => "red",
1 => "blue",
2 => "green",
_ => return Err("unknown color"),
};
The expression arms need to be the same type (or what is the type of `name`?). So now the type of the last branch is !. (Which as you hopefully learned from TFA, coerces to any type, here, to &str.)
There's more ways this "block statements are actually expressions" is useful. The need not be a ternary operator / keyword (like C, C++, Python, JS, etc.):
let x = if cond { a } else { b };
In fact, if you're familiar with JavaScript, there I want this pattern, but it is not to be had:
const x; // but x's value will depend on a computation:
// This is illegal.
if(foo) {
x = 3;
} else {
x = 4;
}
// It's doable, but ugly:
const x = (function() { if(foo) { return 3; } else { return 4; }})();
// (Yes, you can do this example with a ternary.
// Imagine the if branches are a bit more complicated than a ternary,
// e.g., like 2 statements.)
Similarly, loops can return a value, and that's a useful pattern sometimes:
let x = loop {
// e.g., find a value in a datastructure. Compute something. Etc.
if all_done {
break result;
}
};
And blocks:
let x = {
// compute x; intermediate variables are properly scoped
// & cleaned up at block close.
//
// There's also a slight visual benefit of "here we compute x" is
// pretty clearly denoted.
};
> Even if you disagree with this argument, this design decision has resulted in all these weird/confusing but absolutely useless code examples
I think one can cook up weird code examples in any language.
What Rust's syntax really reminds me of is Algol 68, or BLISS, both of them being these old procedural languages where everything is an expression. The "loop { ... break expr; ... }" thing reminds me of BLISS's "exitloop expr" construct.
There's so many programming languages (low barrier to create) that there's a ton of overlap and evolutionary changes/similarities between them. I was thinking of perl's "do { x } while foo" style constructs in this particular case.
I am incredibly amused that I got downvoted to -1 for mentioning perl though. People here are Weird.
> What practical value is it to users to allow "return <expr>" to itself be an expression?
Now, what if I need to return an error?
The expression arms need to be the same type (or what is the type of `name`?). So now the type of the last branch is !. (Which as you hopefully learned from TFA, coerces to any type, here, to &str.)There's more ways this "block statements are actually expressions" is useful. The need not be a ternary operator / keyword (like C, C++, Python, JS, etc.):
In fact, if you're familiar with JavaScript, there I want this pattern, but it is not to be had: Similarly, loops can return a value, and that's a useful pattern sometimes: And blocks: > Even if you disagree with this argument, this design decision has resulted in all these weird/confusing but absolutely useless code examplesI think one can cook up weird code examples in any language.