Use "IIFE", not "break from labeled blocks"

Rust 1.65 add a feature that allow break from labeled blocks, but I don't think it's a good idea. We can do the same thing by using immediately invoked function expression.

Example in announcement:

let result = 'block: {
    do_thing();
    if condition_not_met() {
        break 'block 1;
    }
    do_next_thing();
    if condition_not_met() {
        break 'block 2;
    }
    do_last_thing();
    3
};

Better writing (I think)

let result = (||{
    do_thing();
    if condition_not_met() {
        return 1;
    }
    do_next_thing();
    if condition_not_met() {
        return 2;
    }
    do_last_thing();
    3
})();

We shouldn't add more rules while we can do it normally now. Especially, should not be ugly!!!

Maybe way (function with no parameters and parentheses express IIFE)

let result = fn{
    do_thing();
    if condition_not_met() {
        return 1;
    }
    do_next_thing();
    if condition_not_met() {
        return 2;
    }
    do_last_thing();
    3
};

Labeled breaks already existed for loop constructs, so this wasn't a unique new feature, but a generalization of an existing one. Additionally, closures are less powerful than labeled break, as you cannot nest them and break from an outer one or return from the containing function. (This is important especially with e.g. ? targeting the closure rather than the containing function.)

In any case, the feature is stable and isn't going to be removed. The unstable period and FCP was the time to discuss if a feature pulls its weight. (And labeled block breaks is a trivial extension of labeled loop breaks with basically zero questions as to what semantics it has.)

You can still use IIFE if you want. Most devs will agree that most often you'd be better introducing a new function or otherwise restructuring your code than using labeled block break, but in the cases it's useful it's invaluable (to the point of people abusing loop to emulate the functionality).

25 Likes

Thank you for reply. I think your view point is valuable. I will study your first paragraph.

Although that, I think "break" should only be used in iteration (for, while, loop). It's abuse when use in other place.

A similar construct exists even in Java and I didn't observe any frequent use or abuse. Maybe because it is indeed obscure and most developers even don't know it is possible.

Anyway, there are cases when it can be useful and make things actually more straightforward.

That's how you end up with things like

'label: loop {
    break {
        // This is now the same as a labeled block you can break from.
    }
}

Which construct are you referring to?

1 Like

That doesn't always work due to the borrow checker. It also makes it less clear which block you are jumping out of, prevents returning from the outer function and doesn't allow breaking out of multiple nested blocks.

2 Likes

To be quite honest, I find "IIFE" scarcely more than a hack originally invented to work around the lack of sane block scoping in a very specific language (JS) known for a lack of sane things. Using an immediately-called closure to emulate early exit from a block is just as hacky as using a single-iteration loop to do the same. Both "patterns" are using a language feature meant for doing one thing to do another thing in an unorthogonal manner.

20 Likes

Why? How is breaking from the middle of a loop better than breaking from the middle of a block?

4 Likes

Two comments on this:

  1. It's too late. Now that it's stable it's not being removed. The last time for this feedback was when the feature was in Final Comment Period -- which exists exactly to elicit feedback from the community about the feature. The FCP for the feature was mentioned in TWiR #456. If you're interested in providing comments on features proposed-for-stabilization, I suggest watching TWiR and trying out the various things as they come up. (Of course you can also try them out in nightly well before the stabilization conversations too!)

  2. The tracking issue has over 4 years worth of discussion about the feature. It was originally proposed for stabilization back in 2018, which ended up not happening due to concerns like whether it pulls its weight. However, further experience with it later resulted in some of those people changing their minds sometimes after about a year and sometimes multiple years later about whether it's a good idea. The core "just rewrite it better" objection was thus discussed extensively over literally years, and was definitely not missed or discarded in haste.

I actually agree that if one is considering this, then it's probably worth thinking about a refactoring instead. But such a refactoring isn't always better. As I said when signing off on this feature,

So this isn't something I want to see often in Rust code, but I think it's well worth supporting for those few places where it's appropriate, since the cost seems to be low to me.

15 Likes

To be honest we're already using IIFE in Rust to work around the lack of block scoping of the ? operator. :face_holding_back_tears:

2 Likes

One day Rust may have try blocks

2 Likes

Break with a labelled block. This is a perfectly valid Java code (assuming bar is a Boolean variable):

foo: {
    if (bar) {
        break foo;
    }

    // Do more stuff if !bar
}
1 Like

Yes, IIFE has less power than break label block. But we don't reach it in most of time. Code in break label block usually small, we use IIFE is enough. Break label block is not necessary (I mean you can use other skill instead, break label block does not let that be concise, at least in code words).

In most languages, that's it. Someone use break label block in iteration, maybe will ignore block name after break, and think this line will break iteration, as he/she don't know this new feature. Using break in other place is not friendly to newcomers.

I don't think they are same thing. I think IIFE is a trick, but loop is a abuse when we execute one-time code. Loop has incorrect semantic here. I think best way is add a new keyword - once, but it looks not worth to do.

Thank you, I didn't know that before. I think it's good idea, only not sure that try keyword is truly suitable.

Thank you very much for let me know more. I don't know much about that, I will read those links.