But priorities have shifted from getting a stable feature set, to making things nicer, so I think this deserves another look
the idea is to have loops like this:
loop match expr {
Foo(x)=>{...}
Bar(x)=>{...}
}
for match in iter_expr {
Foo(x)=>{...}
Bar(x)=>{...}
}
which would roughly desugar to:
loop {
match expr {
Foo(x)=>{...}
Bar(x)=>{...}
}
}
for item in iter_expr {
match item {
Foo(x)=>{...}
Bar(x)=>{...}
}
}
It'd be good for dropping a level of braces for event loops and such
the for loop syntax i'm suggesting here is definitely more awkward than loop. it'd be nice to have some consistency and allow a match to replace any block (if/else bodies, functions, while loops, etc), but i can't think of a nice syntax for those cases.
Well, if and while don't bind anything, so this doesn't really apply there. For functions, well, at least for single argument closures one could use something like |match| { /* match arms */}. This has some precedent in Haskell, I've explained it in more detail in this post in a thread that was also about eliminating extra indentation levels:
Thinking about it again now, one could even consider supporting e. g. |match, match, match| { (a, b, c) => {...} }, bundling up multiple values in a tuple.
And one could go much further and generalize this to allowing match as a pattern in general in some places, e. g.
while let Some(match) = foo.next() {
0 => {
bar1();
bar2();
}
n => baz(n),
}
and similar for if let and even function definitions
Edit: Going back to discussing your suggestions, this generalization would mean the for syntax stays as you proposed, and the loop match expr { ... } needs to be written as while let match = expr { ... }. Admitted, that's a bit of a keyword zoo, and a bit too while true-style, so perhaps loop match could be a new “abbreviation” of while let match =.
i was kinda thinking of something like the thread you linked. (if <cond> match <expr> { })
but i'm not a fan of that syntax, since it'd easily encourage either long lines or "goto fail" indentation
the single-argument lambda match (or first argument?) seem nice to me.
i think i have a strong preference for keywords to show up at the beginning of the expression, so they can't hide as easily
loop match seems logical to me, because that's just optional braces. However, I don't write loop that often to appreciate a special shorthand syntax for it.
I can see else match or else <keyword> {} in general being a useful syntax sugar, and it wouldn't be too weird, because else if already exists in Rust, and C is even more permissive here.
However, I needed a triple double-take for for match and fn match. That's an unusual, very dense syntax. A magic variable name that changes syntax of a next block is too much for me.
I do like the idea of being able to write top-level matches more easily, but this syntax feels like it optimizes for writing at the expense of reading.
For me one of the biggest use of loop is to handle the lack of a default case in a for loop. IMO new syntax around for and loop should first try to solve that:
'outer: loop {
for item in list {
if cond { break 'outer f(item); }
}
break default_val();
}
oh, i didn't parse it that way, but i can see how it'd be very easy to
i parsed it as (for match) in expr. like, a 2 word keyword. but it's just lowercase letters, so if you're not looking at it with syntax highlighting, it'd easily look like a variable name
maybe dropping the for would work better, and have match in be a thing?
match in iter_expr {
Foo(x)=>{...}
Bar(x)=>{...}
}
that would be useful for Option<Enum> and Result<Enum> code, which comes up often. i almost want it to handle the unwrapping, but no decent syntax is coming to mind
if x.is_none() {
...
}
else match x.unwrap() {
Foo(x)=>{...}
Bar(x)=>{...}
}
i like the match closures from there:
xs.map(match {
Foo(x)=>{...}
Bar(x)=>{...}
})
maybe less of a big deal, since you're not saving a level of indentation/braces on a closure like that
This is definitely not a case that needs "shorter syntax". A loop is a loop, a match is a match, and if you need both, you can just compose them.
Composability (which is already one of Rust's strengths) is a much better alternative over adding syntax for every possible combination of control structures. It's clearer and easier to learn/teach as well as easier to change.
If you have too much indentation in your code, the solution is not to incoherently lump together unrelated parts of it. The solution is to refactor and modularize. Too clever and dense code won't become higher-quality due to more syntactic sugar and cleverness (arguably, that only makes it worse). It becomes higher-quality due to design effort put into it being higher-quality.
Unfortunately neither of the syntax you proposed to simplify 'outer: loop { for ... { if ... { break 'outer ...; }; break ...; } works easily if you have any function inside that use the ? operator because lambdas can’t interact with the control flow of the caller.
I took a look at this proposal, as well as the link posted by @steffahn in the second post. While I agree that removing extra level of braces/indentation would be nice, I don’t think that loop match or for match should get specific syntax.
I am now highly off-topic, but personally the think that annoys me the most in term of extra indentation is this pattern:
match x {
None => {
return Err(...); // short exit early
},
Some(x) => {
// use the unwrapped x
...
// most of the code now has 2 extra level of indentation
},
}
That’s two extra level of unwanted indentation, because lambda can’t modify the control flow of the caller. Assuming that the hypothetical inline keyword could do such thing, here is the kind of syntax I’d like:
let x = x.unwrap_or(inline || {
return Err(...);
});
// x in now unwrapped
// the rest of the function doesn’t have extra indentation.
I will keep this is mind. That’s probably what I need. I’m surprised I didn’t saw it mentioned (maybe it was) in the last if/unless discussion I read here. If it effectively works everitime, you made my day!
It's a lot less verbose than your original… (and I'm now confused, because you originally wanted to reduce spurious indentation, so I'm
feeling like we've got a moving goalpost here.)