New syntax, overview:
break; // normal
break => value; // when returning a value from the current block
break label; // when breaking a labeled block
break label => value; // when returning a value from labeled block
// break :label; <- the colon prefix would not be necessary anymore.
Pros:
=> insteadblk: { ... } or outer: while(... stays as beforeswitch(cond) { true => 5, else => 10,};Cons:
Example usage, taken from examples in the language reference:
fn rangeHasNumber(begin: usize, end: usize, number: usize) bool {
var i = begin;
return while (i < end) : (i += 1) {
if (i == number) {
break => true;
}
} else false;
}
test "nested break" {
outer: while (true) {
while (true) {
break outer; // no '=>', so outer has to be a label
}
}
// ...
}
test "labeled break from labeled block expression" {
var y: i32 = 123;
const x = blk: {
y += 1;
break blk => y; // imagine blk with same syntax highlighting color as `blk:` here
};
}
More intuitive and easier to remember (at least my opinion)
I personally have to think "where does the colon go again?" pretty much every time I write a labeled break.
Food for thought: Odin's original idea for returning a value from a control construct was to use give:
const val = {
give 32;
};
assert(val == 32);
const val = blk: {
if (true) {
give blk 32;
}
};
Certainly though, the :blk always seemed awkward to me too.
Food for thought: Odin's original idea for returning a value from a control construct was to use
give
Right now only loop control has an anonymous label, then why not assign an anonymous label to assignment as well?
const x = blk_x: if (...) {
... // a few lines of code
break => option_a;
} else {
... // many lines of code
break blk_x => option_b;
};
const y = blk_y: {
...
const tmp = while (...) {
...
if (...) break => loop_result;
...
};
... // many lines of code
break blk_y => result;
};
@iology I'm not sure I follow.
@Tetralux No problem. I shouldn't say the assignment is labeled anonymously. :P
I have just found out that break can already work with any labeled blocks {...} so what I really want is:
support outer_label: for/while/if/switch (...)
add an anonymous label to the blocks binded to an assignment:
const x = (anonymous label:) {
...
};
const x = (anonymous label:) if {
...
} else {
...
};
Sorry for the confusion!
I have no idea whether this is feasible in zig, but I would suggest considering how Rust does this: the presence or absence of a semi-colon after the last expression in a block determines whether the block returns the value of the expression or not.
@donaldcallen That was how Zig worked originally, but it was changed because it made it hard to tell the difference between a block returning the result of an if/while/for expression and a block with an if/while/for statement at the end. Here's the original issue.
I see there are some (-1) reactions to this issue, but no explanations yet as to why it might be better to stick with status quo.
How about we just make the colon consistent?
const x = blk: {
y += 1;
break blk: y;
}
// or
const x = :blk {
y += 1;
break :blk y;
}
How about we just make the colon consistent?
Colon after the label would look strange when not breaking with a value:
blk: {
y += 1;
break blk:;
}
and colon before the label would look a bit strange for e.g. labeled loops:
:outer while (true) {
while (true) {
break :outer;
}
}
Edit: kindly ignore this. You could also require label names to start with a special sigil to gain conciseness and ditch the colon entirely:
````zig
break; // normal
break value; // when returning a value from the current block
break #label; // when breaking a labeled block
break #label value; // when returning a value from labeled block
break #; // maybe
````
How about we just make the colon consistent?
const x = blk: { y += 1; break blk: y; } // or const x = :blk { y += 1; break :blk y; }
I sort of think of blk: and break :blk that there is something in between those two :'s, and that it thus makes sense to at the declaration of the block, have it after the block name, and when you break out, have it before the block name. I think that it feels quite symmetric this way, even though it may be unintuitive at first. But mayhaps better documentation on where the : goes at which place would help quite a bit for newer people.
But mayhaps better documentation on where the : goes at which place would help quite a bit for newer people.
Worth noting that I fairly often get it the wrong way around, despite not being new to Zig.
Perhaps we can just remove the colon from the break usage?
const val = blk: {
break blk 31;
};
This cannot be confused with breaking with a single value, because there's two values given to break, plus, you presumably couldn't have another variable called blk, because of the shadowing rules.
Further, this also makes things more consistent, since, as an illustration:
const Int = @IntType(32, false);
const i: Int = 40; // We don't have to specify `@` anywhere here, despite using `Int`!
// The name has been bound, and that's that.
const val = blk: {
break blk 42; // We don't have to specify `:` anywhere here, despite using `blk`!
// The name has been bound, and that's that.
}
So there's symmetry to be gained here.
Most helpful comment
I personally have to think "where does the colon go again?" pretty much every time I write a labeled break.