New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

RFC: label-break-value #2046

Merged
merged 7 commits into from Feb 27, 2018

Conversation

@ciphergoth
Contributor

ciphergoth commented Jun 26, 2017

Rendered

Tracking issue: rust-lang/rust#48594

Allow a break not only out of loop, but of labelled blocks with no loop. Like loop, this break can carry a value.

See also Pre-RFC discussion.

Status as of 2018-01-18.

@ciphergoth ciphergoth changed the title from label-break-value RFC to RFC: label-break-value Jun 26, 2017

@mark-i-m

This comment has been minimized.

Show comment
Hide comment
@mark-i-m

mark-i-m Jun 27, 2017

Contributor

This feels to much like a goto. I don't really want Rust == Fortran 😛

Contributor

mark-i-m commented Jun 27, 2017

This feels to much like a goto. I don't really want Rust == Fortran 😛

@scottmcm

This comment has been minimized.

Show comment
Hide comment
@scottmcm

scottmcm Jun 27, 2017

Member

@mark-i-m Is there something particular about this proposal that makes it feel too goto-like?

This seems to have the same restrictions as the labeled break we already have, as well as to normal break and return: cannot go backwards, cannot skip variable definitions, can only exit a syntactically-visible {} block. (Or, more abstractly, that it doesn't violate the "progress of the process remains characterized by a single textual index" property from Go To Considered Harmful.)

Member

scottmcm commented Jun 27, 2017

@mark-i-m Is there something particular about this proposal that makes it feel too goto-like?

This seems to have the same restrictions as the labeled break we already have, as well as to normal break and return: cannot go backwards, cannot skip variable definitions, can only exit a syntactically-visible {} block. (Or, more abstractly, that it doesn't violate the "progress of the process remains characterized by a single textual index" property from Go To Considered Harmful.)

@eddyb

This comment has been minimized.

Show comment
Hide comment
@eddyb

eddyb Jun 27, 2017

Member

The problems with goto are more or less those of safety. Rust doesn't have the same issues.
Besides you can already do this with loop { break {...} }, the difference is purely in ergonomics.

Member

eddyb commented Jun 27, 2017

The problems with goto are more or less those of safety. Rust doesn't have the same issues.
Besides you can already do this with loop { break {...} }, the difference is purely in ergonomics.

@mark-i-m

This comment has been minimized.

Show comment
Hide comment
@mark-i-m

mark-i-m Jun 27, 2017

Contributor

that it doesn't violate the "progress of the process remains characterized by a single textual index" property from Go To Considered Harmful

This is a fair point, but I feel more strongly, I guess.

I personally don't like the labeled breaks we already have. IMHO, they usually just make control flow harder to follow/write/debug without really providing any benefit, which is the heart of Dijkstra's point. In fact, I would go so far as to say, that I generally dislike normal break/continue, too, but I accept them for lack of a better alternative. The way I see it, the more entry/exit points you have for a loop, the worse code quality is -- it's just becomes convoluted to reason about loop invariants.

Contributor

mark-i-m commented Jun 27, 2017

that it doesn't violate the "progress of the process remains characterized by a single textual index" property from Go To Considered Harmful

This is a fair point, but I feel more strongly, I guess.

I personally don't like the labeled breaks we already have. IMHO, they usually just make control flow harder to follow/write/debug without really providing any benefit, which is the heart of Dijkstra's point. In fact, I would go so far as to say, that I generally dislike normal break/continue, too, but I accept them for lack of a better alternative. The way I see it, the more entry/exit points you have for a loop, the worse code quality is -- it's just becomes convoluted to reason about loop invariants.

@mark-i-m

This comment has been minimized.

Show comment
Hide comment
@mark-i-m

mark-i-m Jun 27, 2017

Contributor

I should add that by breaking out of the middle of a block, you have effictively made it into 2 blocks, one of which doesn't always happen. And that is not always syntactically obvious, IMHO...

Contributor

mark-i-m commented Jun 27, 2017

I should add that by breaking out of the middle of a block, you have effictively made it into 2 blocks, one of which doesn't always happen. And that is not always syntactically obvious, IMHO...

@ciphergoth

This comment has been minimized.

Show comment
Hide comment
@ciphergoth

ciphergoth Jun 27, 2017

Contributor

Full text of Go To Statement Considered Harmful - very interesting!

Contributor

ciphergoth commented Jun 27, 2017

Full text of Go To Statement Considered Harmful - very interesting!

@ciphergoth

This comment has been minimized.

Show comment
Hide comment
@ciphergoth

ciphergoth Jun 27, 2017

Contributor

I filed a Pre-RFC about this, see also discussion there.

Contributor

ciphergoth commented Jun 27, 2017

I filed a Pre-RFC about this, see also discussion there.

Delete superfluous paragraph
 link to discussions in discussions instead.
@ciphergoth

This comment has been minimized.

Show comment
Hide comment
@ciphergoth

ciphergoth Jun 27, 2017

Contributor

Other discussions: I proposed this here. An identical proposal was part of the explanation for trait based exception handling.

Contributor

ciphergoth commented Jun 27, 2017

Other discussions: I proposed this here. An identical proposal was part of the explanation for trait based exception handling.

@golddranks

This comment has been minimized.

Show comment
Hide comment
@golddranks

golddranks Jun 27, 2017

I think that making control flow more flexible is generally a good thing. As already argued by others Dijkstra's critique doesn't apply here; the critique is against obfuscating the program state using surprising control paths. In the context of this feature it's only allowed to break outwards from a scope, which doesn't allow witnessing uninitialised variables or skipping in the middle of some code that expects there to be a state set up by the earlier code. It does allow skipping some code in a possibly "surprising way" the sense that one can jump from an inner scope to the grandparent scope, but unlike exceptions, this is still a local feature that is well visible in the local context – so in the end, it hardly isn't actually surprising, and when used with discretion, can lead to cleaner code.

I'd argue, that without flexible and safe control flow constructs, people tend to store the "which path" information to local flags or use inner functions to be able to return early. These both feel like hacks to me. The problem with manually juggling control flow flags is that the compiler can't hardly reason about their state and the problem with functions is that they are a wrong abstraction – they come with a new stack frame and aren't easily able to access the parent frame unless the state is explicitly passed to them. They are too heavyweight. Having labelled breaks is a nice way to retain the "state machine-y" feeling of a function-local control flow but still allow more flexible flow that comes handy from time to time.

golddranks commented Jun 27, 2017

I think that making control flow more flexible is generally a good thing. As already argued by others Dijkstra's critique doesn't apply here; the critique is against obfuscating the program state using surprising control paths. In the context of this feature it's only allowed to break outwards from a scope, which doesn't allow witnessing uninitialised variables or skipping in the middle of some code that expects there to be a state set up by the earlier code. It does allow skipping some code in a possibly "surprising way" the sense that one can jump from an inner scope to the grandparent scope, but unlike exceptions, this is still a local feature that is well visible in the local context – so in the end, it hardly isn't actually surprising, and when used with discretion, can lead to cleaner code.

I'd argue, that without flexible and safe control flow constructs, people tend to store the "which path" information to local flags or use inner functions to be able to return early. These both feel like hacks to me. The problem with manually juggling control flow flags is that the compiler can't hardly reason about their state and the problem with functions is that they are a wrong abstraction – they come with a new stack frame and aren't easily able to access the parent frame unless the state is explicitly passed to them. They are too heavyweight. Having labelled breaks is a nice way to retain the "state machine-y" feeling of a function-local control flow but still allow more flexible flow that comes handy from time to time.

@eddyb

This comment has been minimized.

Show comment
Hide comment
@eddyb

eddyb Jun 27, 2017

Member

@ciphergoth In fact my first instinct for desugaring catch is that there's a label on it (or at least the compiler has a way to refer to it) and ? uses break 'innermost_catch err instead of return err.
I haven't looked much into how it ended up being implemented but AFAIK it's close enough.
The advantage of a proposal like this is that you can go to one of many labels instead of just one.

Member

eddyb commented Jun 27, 2017

@ciphergoth In fact my first instinct for desugaring catch is that there's a label on it (or at least the compiler has a way to refer to it) and ? uses break 'innermost_catch err instead of return err.
I haven't looked much into how it ended up being implemented but AFAIK it's close enough.
The advantage of a proposal like this is that you can go to one of many labels instead of just one.

@ciphergoth

This comment has been minimized.

Show comment
Hide comment
@ciphergoth

ciphergoth Jun 27, 2017

Contributor

@eddyb The RFC that proposes catch invents pretty much exactly what I propose here in order to describe what it does. It also describes return in terms of a break to a special 'fn scope for the whole function.

In the pre-RFC discussion, nikomatsakis says:

The compiler already internally supports [labelled blocks] for use with catch { } (that is how the HIR represents catch).

Contributor

ciphergoth commented Jun 27, 2017

@eddyb The RFC that proposes catch invents pretty much exactly what I propose here in order to describe what it does. It also describes return in terms of a break to a special 'fn scope for the whole function.

In the pre-RFC discussion, nikomatsakis says:

The compiler already internally supports [labelled blocks] for use with catch { } (that is how the HIR represents catch).

@withoutboats withoutboats added the T-lang label Jun 27, 2017

@mark-i-m

This comment has been minimized.

Show comment
Hide comment
@mark-i-m

mark-i-m Jun 28, 2017

Contributor

@golddranks

As already argued by others Dijkstra's critique doesn't apply here; the critique is against obfuscating the program state using surprising control paths.

Perhaps I will always just disagree on this... I suspect I am probably more extreme than most on this point. It looks like I am pretty outnumbered here, so I wont spam everyone more beyond this post, unless asked for more 😛

Basically, I can't imagine many useful situations where this is easier to follow

'block: {
    do_thing();
    if condition_not_met() {
        break 'block;
    }
    do_next_thing();
    if condition_not_met() {
        break 'block;
    }
    do_last_thing();
}

than this

do_thing();

if condition_met() {
    do_next_thing();
    if condition_met() {
        do_last_thing();
    }
}

In the first example it's not clear that the preconditions for do_last_thing are the conditions_met1() && conditions_met2(). It is also a bit annoying that syntactically non-obvious prefixes of a block might execute.

But in the second one, the curly braces (and formatting conventions) make it clear, which is what we expect because curly braces are the primary way rust indicates a block of code. Of course someone will argue that if you have 50 of them, you will have too much indenting. I thinks it's worth it, but I think that's really a matter of taste.

Contributor

mark-i-m commented Jun 28, 2017

@golddranks

As already argued by others Dijkstra's critique doesn't apply here; the critique is against obfuscating the program state using surprising control paths.

Perhaps I will always just disagree on this... I suspect I am probably more extreme than most on this point. It looks like I am pretty outnumbered here, so I wont spam everyone more beyond this post, unless asked for more 😛

Basically, I can't imagine many useful situations where this is easier to follow

'block: {
    do_thing();
    if condition_not_met() {
        break 'block;
    }
    do_next_thing();
    if condition_not_met() {
        break 'block;
    }
    do_last_thing();
}

than this

do_thing();

if condition_met() {
    do_next_thing();
    if condition_met() {
        do_last_thing();
    }
}

In the first example it's not clear that the preconditions for do_last_thing are the conditions_met1() && conditions_met2(). It is also a bit annoying that syntactically non-obvious prefixes of a block might execute.

But in the second one, the curly braces (and formatting conventions) make it clear, which is what we expect because curly braces are the primary way rust indicates a block of code. Of course someone will argue that if you have 50 of them, you will have too much indenting. I thinks it's worth it, but I think that's really a matter of taste.

@est31

This comment has been minimized.

Show comment
Hide comment
@est31

est31 Jun 28, 2017

Contributor

@mark-i-m In my use case, I need to conditionally break from inside a deeply nested structure, the eno! invocation is 4 layers inside structure, with loops and if's outside. This can't just be simply refactored to use if.

Also, I especially like the pattern to break early if some condition is not met, so that there is no big rightward drift.

Contributor

est31 commented Jun 28, 2017

@mark-i-m In my use case, I need to conditionally break from inside a deeply nested structure, the eno! invocation is 4 layers inside structure, with loops and if's outside. This can't just be simply refactored to use if.

Also, I especially like the pattern to break early if some condition is not met, so that there is no big rightward drift.

@mark-i-m

This comment has been minimized.

Show comment
Hide comment
@mark-i-m

mark-i-m Jun 29, 2017

Contributor

@est31 I'll take your word for it that it is hard to refactor (I haven't tried). I guess I can see the use case, but I still don't really like the break as a pattern... although, I don't have an alternative, other than major refactoring...

Contributor

mark-i-m commented Jun 29, 2017

@est31 I'll take your word for it that it is hard to refactor (I haven't tried). I guess I can see the use case, but I still don't really like the break as a pattern... although, I don't have an alternative, other than major refactoring...

@scottmcm

This comment has been minimized.

Show comment
Hide comment
@scottmcm

scottmcm Jun 29, 2017

Member

@mark-i-m I actually agree with your for that example. Overall, though, I suspect that people won't reach for this except in cases where if and match are awkward too, so it doesn't scare me to have it.

The example I found quite compelling was this one:

let result = 'block: {
    for &v in first_container.iter() {
        if v > 0 { break 'block v; }
    }
    for &v in second_container.iter() {
        if v < 0 { break 'block v; }
    }
    0
}

Because a simple translation to normal constructs ends up something like this:

let mut result = None;
for &v in first_container.iter() {
    if v > 0 {
        result = Some(v);
        break;
    }
}
if result.is_none() {
    for &v in second_container.iter() {
        if v < 0 {
            result = Some(v);
            break;
        }
    }
}
let result = result.unwrap_or(0);

Which I find more awkward, as it obscures the symmetry and has the compiler less able to help with the initialization logic. (You could also do this one with the {||{ … }}() "operator" and return, but I'm not a fan of immediately-called-closure as a pattern either.)

Member

scottmcm commented Jun 29, 2017

@mark-i-m I actually agree with your for that example. Overall, though, I suspect that people won't reach for this except in cases where if and match are awkward too, so it doesn't scare me to have it.

The example I found quite compelling was this one:

let result = 'block: {
    for &v in first_container.iter() {
        if v > 0 { break 'block v; }
    }
    for &v in second_container.iter() {
        if v < 0 { break 'block v; }
    }
    0
}

Because a simple translation to normal constructs ends up something like this:

let mut result = None;
for &v in first_container.iter() {
    if v > 0 {
        result = Some(v);
        break;
    }
}
if result.is_none() {
    for &v in second_container.iter() {
        if v < 0 {
            result = Some(v);
            break;
        }
    }
}
let result = result.unwrap_or(0);

Which I find more awkward, as it obscures the symmetry and has the compiler less able to help with the initialization logic. (You could also do this one with the {||{ … }}() "operator" and return, but I'm not a fan of immediately-called-closure as a pattern either.)

@ciphergoth

This comment has been minimized.

Show comment
Hide comment
@ciphergoth

ciphergoth Jun 29, 2017

Contributor

Should I be changing the examples in the RFC to reflect discussion here?

Contributor

ciphergoth commented Jun 29, 2017

Should I be changing the examples in the RFC to reflect discussion here?

@mark-i-m

This comment has been minimized.

Show comment
Hide comment
@mark-i-m

mark-i-m Jun 30, 2017

Contributor

I think it would be useful to include some of the motivating examples. And I would also like to see the disadvantages section updated, with some of the objections, even if the language is not strongly worded...

Contributor

mark-i-m commented Jun 30, 2017

I think it would be useful to include some of the motivating examples. And I would also like to see the disadvantages section updated, with some of the objections, even if the language is not strongly worded...

Fix broken Rust code with proper references
Various other small improvements
@ciphergoth

This comment has been minimized.

Show comment
Hide comment
@ciphergoth

ciphergoth Jul 1, 2017

Contributor

For the specific example given you could also do this:

first_container.iter().filter(|&&v| v > 0).chain(
        second_container.iter().filter(|&&v| v < 0)
    ).map(|&v| v).next().unwrap_or(0);
Contributor

ciphergoth commented Jul 1, 2017

For the specific example given you could also do this:

first_container.iter().filter(|&&v| v > 0).chain(
        second_container.iter().filter(|&&v| v < 0)
    ).map(|&v| v).next().unwrap_or(0);
@mark-i-m

This comment has been minimized.

Show comment
Hide comment
@mark-i-m

mark-i-m Jul 1, 2017

Contributor
Contributor

mark-i-m commented Jul 1, 2017

@Ericson2314

This comment has been minimized.

Show comment
Hide comment
@Ericson2314

Ericson2314 Jul 3, 2017

Contributor

Big fan of this; thanks for writing!

One nit is while the desugaring is correct, I don't think in long term we should implement/teach/think about the feature that way. I rather have:

  1. Break on block is fundamental

  2. Breaking out of loop is no different than breaking out of underlying block

  3. Break with no label is desugared to innermost loop instead of innermost block for historical reasons.

RFC language can be incremental I suppose, but o hope something like that makes the books.

Contributor

Ericson2314 commented Jul 3, 2017

Big fan of this; thanks for writing!

One nit is while the desugaring is correct, I don't think in long term we should implement/teach/think about the feature that way. I rather have:

  1. Break on block is fundamental

  2. Breaking out of loop is no different than breaking out of underlying block

  3. Break with no label is desugared to innermost loop instead of innermost block for historical reasons.

RFC language can be incremental I suppose, but o hope something like that makes the books.

@ciphergoth

This comment has been minimized.

Show comment
Hide comment
@ciphergoth

ciphergoth Jul 3, 2017

Contributor

Ericson2314 - how do we integrate continue into that teaching plan?

Maybe we could describe loops as being implicitly this:

'outer: {
    for i in container.iter() {
        'inner: {
            LOOP BODY
        }
    }
}

Then break means break 'outer and continue means break 'inner. continue 'label really means something like continue 'label_inner.

Contributor

ciphergoth commented Jul 3, 2017

Ericson2314 - how do we integrate continue into that teaching plan?

Maybe we could describe loops as being implicitly this:

'outer: {
    for i in container.iter() {
        'inner: {
            LOOP BODY
        }
    }
}

Then break means break 'outer and continue means break 'inner. continue 'label really means something like continue 'label_inner.

@rfcbot

This comment has been minimized.

Show comment
Hide comment
@rfcbot

rfcbot Feb 14, 2018

🔔 This is now entering its final comment period, as per the review above. 🔔

rfcbot commented Feb 14, 2018

🔔 This is now entering its final comment period, as per the review above. 🔔

@bstrie

This comment has been minimized.

Show comment
Hide comment
@bstrie

bstrie Feb 21, 2018

Contributor

@alercah Can you take the examples given in the RFC and mock up equivalents using the catch variant that you're proposing? After all, these RFCs exist solely for ergonomics, and people are going to tend to favor whatever is most pleasant to use.

Contributor

bstrie commented Feb 21, 2018

@alercah Can you take the examples given in the RFC and mock up equivalents using the catch variant that you're proposing? After all, these RFCs exist solely for ergonomics, and people are going to tend to favor whatever is most pleasant to use.

@alercah

This comment has been minimized.

Show comment
Hide comment
@alercah

alercah Feb 21, 2018

Contributor

I was thinking something like (note that I'm using do catch per the proposal for catch, but I'd love to see better syntax):

  let i = 'label: do catch {
    if cond {
      break 'label 3;
    }
    // ...
    val()
  }

It's a little bit more verbose, but if you make break always break to catch, then you don't need the no-unlabeled-break rule:

  for i in 1..10 {
    'label: do catch {
        if cond {
          break;
        }
    }
  }

This would be much less dangerous for misinterpretation.

Contributor

alercah commented Feb 21, 2018

I was thinking something like (note that I'm using do catch per the proposal for catch, but I'd love to see better syntax):

  let i = 'label: do catch {
    if cond {
      break 'label 3;
    }
    // ...
    val()
  }

It's a little bit more verbose, but if you make break always break to catch, then you don't need the no-unlabeled-break rule:

  for i in 1..10 {
    'label: do catch {
        if cond {
          break;
        }
    }
  }

This would be much less dangerous for misinterpretation.

@alercah

This comment has been minimized.

Show comment
Hide comment
@alercah

alercah Feb 21, 2018

Contributor

(I should add: I'm not convinced the idea is better by any means. It was just idle musing.)

Contributor

alercah commented Feb 21, 2018

(I should add: I'm not convinced the idea is better by any means. It was just idle musing.)

@rfcbot

This comment has been minimized.

Show comment
Hide comment
@rfcbot

rfcbot Feb 24, 2018

The final comment period is now complete.

rfcbot commented Feb 24, 2018

The final comment period is now complete.

@Centril Centril referenced this pull request Feb 27, 2018

Open

Tracking issue for RFC 2046, label-break-value #48594

2 of 4 tasks complete

@Centril Centril merged commit 417f92d into rust-lang:master Feb 27, 2018

@Centril

This comment has been minimized.

Show comment
Hide comment
@Centril

Centril Feb 27, 2018

Contributor

Huzzah! The RFC is merged!

Tracking issue: rust-lang/rust#48594

Contributor

Centril commented Feb 27, 2018

Huzzah! The RFC is merged!

Tracking issue: rust-lang/rust#48594

@GuillaumeGomez

This comment has been minimized.

Show comment
Hide comment
@GuillaumeGomez

GuillaumeGomez Feb 28, 2018

Member

So we just added goto in rust. I wish I saw this RFC sooner to comment against it but too late... :-/

Member

GuillaumeGomez commented Feb 28, 2018

So we just added goto in rust. I wish I saw this RFC sooner to comment against it but too late... :-/

@Centril

This comment has been minimized.

Show comment
Hide comment
@Centril

Centril Feb 28, 2018

Contributor

So we just added goto in rust.

Honestly, I don't think that is a fair description =)

Contributor

Centril commented Feb 28, 2018

So we just added goto in rust.

Honestly, I don't think that is a fair description =)

@rpjohnst

This comment has been minimized.

Show comment
Hide comment
@rpjohnst

rpjohnst Feb 28, 2018

One of the reasons goto makes things harder is because it allows for irreducible control flow. Not only does this make reading the code harder for humans, but it makes the compiler's job more complicated.

Fortunately, label-break-value does not allow for irreducible control flow. It's hardly any different from early returns, just applied at the expression level.

rpjohnst commented Feb 28, 2018

One of the reasons goto makes things harder is because it allows for irreducible control flow. Not only does this make reading the code harder for humans, but it makes the compiler's job more complicated.

Fortunately, label-break-value does not allow for irreducible control flow. It's hardly any different from early returns, just applied at the expression level.

@mark-i-m

This comment has been minimized.

Show comment
Hide comment
@mark-i-m

mark-i-m Feb 28, 2018

Contributor

It's hardly any different from early returns, just applied at the expression level.

Needless to say, not everyone agrees, but it is done already, and the debate has already been had...

Contributor

mark-i-m commented Feb 28, 2018

It's hardly any different from early returns, just applied at the expression level.

Needless to say, not everyone agrees, but it is done already, and the debate has already been had...

@rpjohnst

This comment has been minimized.

Show comment
Hide comment
@rpjohnst

rpjohnst Feb 28, 2018

The point I'm making is not a matter of opinion- label-break-value does nothing to the control flow graph that early returns don't already do, especially when you consider inlining.

You can argue the subjective costs and benefits to humans of it all day long, which is why I thought I'd point out an objective way to look at it.

rpjohnst commented Feb 28, 2018

The point I'm making is not a matter of opinion- label-break-value does nothing to the control flow graph that early returns don't already do, especially when you consider inlining.

You can argue the subjective costs and benefits to humans of it all day long, which is why I thought I'd point out an objective way to look at it.

@est31

This comment has been minimized.

Show comment
Hide comment
@est31

est31 Feb 28, 2018

Contributor

Previously, I was emulating the feature with a loop { /*code*/ if condition { break; } /*more code */ break; }. With labeled blocks I can simplify this to 'outer { /*code*/ if condition { break 'outer; } /*more code */ }. Neither of the two is goto, you can only jump back and scoping questions are immediately clear and resolved. I hate goto and wouldn't want it in the language, but this RFC is no goto.

Contributor

est31 commented Feb 28, 2018

Previously, I was emulating the feature with a loop { /*code*/ if condition { break; } /*more code */ break; }. With labeled blocks I can simplify this to 'outer { /*code*/ if condition { break 'outer; } /*more code */ }. Neither of the two is goto, you can only jump back and scoping questions are immediately clear and resolved. I hate goto and wouldn't want it in the language, but this RFC is no goto.

@scottmcm

This comment has been minimized.

Show comment
Hide comment
@scottmcm

scottmcm Feb 28, 2018

Member

@GuillaumeGomez See related previous discussion above: #2046 (comment)

Member

scottmcm commented Feb 28, 2018

@GuillaumeGomez See related previous discussion above: #2046 (comment)

@SoniEx2

This comment has been minimized.

Show comment
Hide comment
@SoniEx2

SoniEx2 Mar 1, 2018

if statements are glorified gotos. it doesn't matter what language they're in.

here's a lua example because I'm too lazy to write a rust example when I can use an existing example. https://gist.github.com/SoniEx2/fc5d3614614e4e3fe131/#file-special-lua-L11-L71

labeled blocks are just IIFEs on steroids.

SoniEx2 commented Mar 1, 2018

if statements are glorified gotos. it doesn't matter what language they're in.

here's a lua example because I'm too lazy to write a rust example when I can use an existing example. https://gist.github.com/SoniEx2/fc5d3614614e4e3fe131/#file-special-lua-L11-L71

labeled blocks are just IIFEs on steroids.

@GuillaumeGomez

This comment has been minimized.

Show comment
Hide comment
@GuillaumeGomez

GuillaumeGomez Mar 2, 2018

Member

Yes I saw it, I commented after. I just don't like the feature, but it's nothing more than an opinion in a sea of opinions. I just wanted to comment and so did I. :)

Member

GuillaumeGomez commented Mar 2, 2018

Yes I saw it, I commented after. I just don't like the feature, but it's nothing more than an opinion in a sea of opinions. I just wanted to comment and so did I. :)

@mark-i-m

This comment has been minimized.

Show comment
Hide comment
@mark-i-m

mark-i-m Mar 2, 2018

Contributor

I think the question is inherently a bit subjective... Does this encourage less-clear-than-it-could-be control flow? (as opposed to an objective question: does this fundamentally introduce new control flow?)

Anyway, I think that the best thing to do now would be to focus on making the feature as good as it can be 🥇

Contributor

mark-i-m commented Mar 2, 2018

I think the question is inherently a bit subjective... Does this encourage less-clear-than-it-could-be control flow? (as opposed to an objective question: does this fundamentally introduce new control flow?)

Anyway, I think that the best thing to do now would be to focus on making the feature as good as it can be 🥇

@SoniEx2

This comment has been minimized.

Show comment
Hide comment
@SoniEx2

SoniEx2 Mar 2, 2018

Does this encourage less-clear-than-it-could-be control flow?

I mean, it allows replacing:

loop {
/* ... */
if cond { break val; }
/* ... */
break otherval;
}

with:

'block: {
/* ... */
if cond { break /*'block?*/ val; }
/* ... */
val
}

So I mean, if you find the former clearer... ;)

SoniEx2 commented Mar 2, 2018

Does this encourage less-clear-than-it-could-be control flow?

I mean, it allows replacing:

loop {
/* ... */
if cond { break val; }
/* ... */
break otherval;
}

with:

'block: {
/* ... */
if cond { break /*'block?*/ val; }
/* ... */
val
}

So I mean, if you find the former clearer... ;)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment