Skip to content

Proposal: disallow implicit references to labeled loops in break and continue #25736

@mlugg

Description

@mlugg

Today, the following is valid Zig:

outer: while (true) {
    while (inner_cond) {
        if (something) {
            break :outer;
        }
    }
    if (something_else) {
        break;
    }
}

Code like that may be a little confusing in some cases; particularly in a long function spanning multiple screens, it's not necessarily immediately obvious what a break refers to. This gets worse if you consider a refactor which eliminates the inner loop:

outer: while (true) {
    // I refactored this code, and now the inner loop is gone
    if (something) {
        // ...but I failed to notice that the label isn't needed here!
        break :outer;
    }
    if (something_else) {
        break;
    }
}

Now it looks like those two break statements must behave differently, but they actually don't!

Proposal

I propose that if a loop is labeled, we require it to always be referenced via that label. If an unlabeled break or continue would target the loop, a compile error is triggered.

This improves readability, because as soon as you see a labeled loop, you know that all control flow targeting that loop will be explicitly marked as such.

outer: while (true) {
    if (something) {
        break :outer;
    }
    if (something_else) {
        // error: break implicitly targets labeled loop
        // note: to target this loop, specify its label with 'break :outer'
        break;
    }
}

An alternative proposal would be disallowing redundant labels on break/continue, so that in the above snippet, the first break was an error due to the redundant :outer. However, I believe that proposal is inferior, because:

  • It means there are still two ways to target this loop which you need to keep in mind when reading code (which one you will see depends on context)
  • It would make it impossible to add a redundant label to a loop for documentation purposes (e.g. retry: while (true) { ... } with continue :retry may be a nice readability aid even if there are no nested loops)

Metadata

Metadata

Assignees

No one assigned

    Labels

    proposalThis issue suggests modifications. If it also has the "accepted" label then it is planned.

    Type

    No type

    Projects

    No projects

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions