Skip to content
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

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

Open
Centril opened this Issue Feb 27, 2018 · 114 comments

Comments

Projects
None yet
@Centril
Copy link
Contributor

Centril commented Feb 27, 2018

This is a tracking issue for RFC 2046 (rust-lang/rfcs#2046).

Steps:

Unresolved questions:

@SoniEx2

This comment has been minimized.

Copy link

SoniEx2 commented Feb 28, 2018

Using "return" would have interesting implications for labeled ? (tryop questionmark operator thingy).

@est31

This comment has been minimized.

Copy link
Contributor

est31 commented Mar 1, 2018

Use return as the keyword instead of break?

@mark-i-m and @joshtriplett have already spoken out against return, but I'll join in given that it is still apparently an unresolved question.

break (and continue) are only usable with a loop.
If you can break something, you can continue it. (I don't think there's an obvious syntax to pick for continue on a block.)

In C, C++, Java, C#, JavaScript and probably more languages you are usually breaking a switch statement in order to prevent fall-through. Rust has solved this much nicer with | in patterns but people coming from those languages won't really see break as something only for for loops. Especially as Java and JavaScript expose the feature via break as well and not return.

The "rules to remember" argument works into the other direction really well however. From what I can tell it is a commonality of the mentioned languages as well as Rust that return only applies to functions and nothing else. So if you see a return, you know that a function is being left.

Labeling a block doesn't cause errors on existing unlabeled breaks

First, I think this happens very rarely as the labeled break feature is admittedly not something that will be used 10 times per 1000 lines. After all, it will only apply to unlabeled breaks that would cross the boundary of the block, not unlabeled breaks inside the block. Second, users of Rust are accustomed to complaints / error messages by the compiler, they will happily fix them! Third (this is the strongest point I think), if instead of labeling a block you wrap it into a loop, you already need to watch out for unlabeled breaks and there is no error message that conveniently lists the break statements, you've got to hunt for them yourself :).

@nikomatsakis

This comment has been minimized.

Copy link
Contributor

nikomatsakis commented Mar 1, 2018

Especially as Java and JavaScript expose the feature via break as well and not return.

This to me is the killer point. break from blocks is a thing in many languages. return from blocks...not so much.

@Centril

This comment has been minimized.

Copy link
Contributor Author

Centril commented Mar 1, 2018

Personally, I share @joshtriplett's view on using break instead of return, but it seemed to me like the discussion hadn't been resolved on the RFC... If you believe the question is resolved in the lang team, tick the box with a note =)

@est31

This comment has been minimized.

Copy link
Contributor

est31 commented Apr 15, 2018

Just saying that I'm working on this. Don't need mentor instructions. Just to not duplicate any efforts. Expect a PR soon.

@scottmcm

This comment has been minimized.

Copy link
Member

scottmcm commented Apr 15, 2018

I'm still in favour of return over break, but I can agree to disagree here. Question resolved.

bors added a commit that referenced this issue May 16, 2018

Auto merge of #50045 - est31:label_break_value, r=eddyb
Implement label break value (RFC 2046)

Implement label-break-value (#48594).
@topecongiro

This comment has been minimized.

Copy link
Contributor

topecongiro commented May 21, 2018

Currently (with rustc 1.28.0-nightly (a1d4a9503 2018-05-20)) rustc does not allow unsafe on a labeled block. Is this expected?

@scottmcm

This comment has been minimized.

Copy link
Member

scottmcm commented May 21, 2018

@topecongiro Yes, I believe it's intentional that this is currently allowed only on plain blocks. It might change in future, but given that this is such a low-level and unusual feature, I'm inclined towards that being a feature rather than a restriction. (On the extreme, I certainly don't want else 'a: {.)

@mark-i-m

This comment has been minimized.

Copy link
Contributor

mark-i-m commented May 21, 2018

Definitely agree. Unsafe + unusual control flow sounds like something to discourage.

In a pinch, though, you could use:

'a: {
unsafe {...}
}

Right?

@SoniEx2

This comment has been minimized.

Copy link

SoniEx2 commented May 22, 2018

Actually, altho else does create a new lexical scope, it's not a block. The whole if-else is a block (kinda). So no, you wouldn't get else 'a: { you'd get 'a: if ... else {.

@eddyb

This comment has been minimized.

Copy link
Member

eddyb commented May 22, 2018

else contains a block (expression). there is no "new lexical scope" without blocks.
An even worse surface syntax position than else would be 'a: while foo 'b: {...}.
(interestingly enough, continue 'a is break 'b, we might want to rely on that at least internally)

@Centril

This comment has been minimized.

Copy link
Contributor Author

Centril commented May 22, 2018

(interestingly enough, continue 'a is break 'b, we might want to rely on that at least internally)

That's a great observation!

@SoniEx2

This comment has been minimized.

Copy link

SoniEx2 commented May 22, 2018

I think labels should be part of block-containing expressions, not blocks themselves. We already have precedent for this with loop. (As it happens, a plain block itself is also a block-containing expression. But things like if and loop are block-containing expressions without being blocks I guess.)

(Things like while or for shouldn't support label-break-value, because they could or could not return a value based on whether they complete normally or with a break.)

@mark-i-m

This comment has been minimized.

Copy link
Contributor

mark-i-m commented May 22, 2018

@eddyb

(interestingly enough, continue 'a is break 'b, we might want to rely on that at least internally)

Only if break 'b re-checks the loop condition...

@eddyb

This comment has been minimized.

Copy link
Member

eddyb commented May 23, 2018

@mark-i-m It's equivalent to 'a: while foo {'b: {...}}, the break wouldn't check the loop condition, the loop itself would, because the loop condition is checked before each iteration of the body block.

@mark-i-m

This comment has been minimized.

Copy link
Contributor

mark-i-m commented May 23, 2018

Woah, I find that highly unintuitive. I expect break 'b to be basically goto 'b, meaning we never exit the loop body and the condition is not checked again...

@mark-i-m

This comment has been minimized.

Copy link
Contributor

mark-i-m commented May 23, 2018

Oh 🤦‍♂️ I see...

@mark-i-m

This comment has been minimized.

Copy link
Contributor

mark-i-m commented May 23, 2018

This is why I don't like labeled break/continue :/

@rpjohnst

This comment has been minimized.

Copy link
Contributor

rpjohnst commented May 23, 2018

Well, we specifically don't have the ability to label these weird inner blocks, so I don't see the problem. break always means "leave this block" and, given the above restriction, there's no way for that to mean anything other than "goto the spot after the associated closing brace."

@mark-i-m

This comment has been minimized.

Copy link
Contributor

mark-i-m commented May 23, 2018

My confusion was not specific to weird inner blocks, but I don't really want to reopen the discussion. That already happened and the community decided to add it.

@SoniEx2

This comment has been minimized.

Copy link

SoniEx2 commented May 24, 2018

Okay, I understand accessibility is a big issue with programming languages... however, labeled break is extremely useful if you write code like me.

So, how can we make labeled break more accessible?

@mark-i-m

This comment has been minimized.

Copy link
Contributor

mark-i-m commented May 24, 2018

So, how can we make labeled break more accessible?

That's a great question. Some ideas I had:

  • We should collect some samples of how people use this in the wild. We can look for undesirable patterns or lazy habits.
  • We should have opinionated style around when it is considered poor practice to use labeled break/continue.
  • We may be able to add lints for some patterns that could be turned into loops/iterator combinators mechanically (I can't think of any such patterns off the top of my head, though).

As a first (admittedly biased) sample, my last (and first) encounter with labeled break in real code was not stellar: https://github.com/rust-lang/rust/pull/48456/files#diff-3ac60df36be32d72842bf5351fc2bb1dL51. I respectfully suggest that if the original author had put in slightly more effort they could have avoided using labeled break in that case altogether... This is an example of the sort of practice I would like to discourage if possible.

@rpjohnst

This comment has been minimized.

Copy link
Contributor

rpjohnst commented May 24, 2018

That's... not labeled break?

@scottmcm

This comment has been minimized.

Copy link
Member

scottmcm commented May 24, 2018

Regarding how break and continue desugar into this, that was also mentioned in the original RFC discussion by the RFC's author; see rust-lang/rfcs#2046 (comment)

@glaebhoerl

This comment has been minimized.

Copy link
Contributor

glaebhoerl commented Jan 5, 2019

If it matters at all: Zig also has this feature.

@joshtriplett

This comment has been minimized.

Copy link
Member

joshtriplett commented Jan 5, 2019

@Centril

This comment has been minimized.

Copy link
Contributor Author

Centril commented Jan 5, 2019

@joshtriplett

We've raised concerns already, and they amount to "this shouldn't be in the language". Those concerns aren't going away.

To be clear I meant registering them with @rfcbot because the bot won't see old concerns registered after a proposal has been canceled. I raised that concern because I know that you have concerns, as a courtesy to you.

I prefer nrc's notion that macros should be able to generate IR. That seems like a completely reasonable solution for this and many future possibilities, without necessarily adding to the surface syntax of the language.

I have no idea what that would look like or that it is a better idea; it seems rather speculative (in the sense of "this might take years before a design is even agreed to") and more costly than the rather low-cost solution of break 'label expr which also has benefits beyond being the result of macro expansion.

@joshtriplett

This comment has been minimized.

Copy link
Member

joshtriplett commented Jan 5, 2019

As a process note for this issue and for all others, please avoid cancelling proposals back and forth... if you don't think something should move forward, just use concerns for that.

I certainly agree with that. However, I don't think a concern is the appropriate mechanism here. A concern seems like "if this were resolved then I'd approve". Here, the issue is "this shouldn't go forward at all, 'merge' is the wrong target, I'd like to 'close' instead". That doesn't seem best handled by the mechanism of a "concern".

@zesterer

This comment has been minimized.

Copy link
Contributor

zesterer commented Jan 6, 2019

@joshtriplett As a point of interest, could you direct me to the concerns that were raised that you mentioned previously? I've gone through the original RFC thread and am unsure what is being specifically referred to. Thanks.

@SoniEx2

This comment has been minimized.

Copy link

SoniEx2 commented Jan 6, 2019

@rfcbot concern ergonomics and optimization/performance (non-rust example of reduced performance and ergonomics https://gist.github.com/SoniEx2/fc5d3614614e4e3fe131#file-special-lua )

idk if I'm using this right

(note how some of the "desugaring" (actually I'd say it's quite the opposite of desugaring - goto is a primitive, loops desugar into goto) is quite awful)

(also note that lua lacks labeled anything so it forces you to use goto. even then, I believe at least one break-block would still be required, but probably with cleaner "desugaring".)

@joshtriplett

This comment has been minimized.

Copy link
Member

joshtriplett commented Jan 6, 2019

@rfcbot concern should-close-not-merge

(As suggested by @Centril on Discord.)

@nrc

This comment has been minimized.

Copy link
Member

nrc commented Jan 6, 2019

I'm not sure if this is an argument in favour of stabilisation or against, but note that this is trivially easy to encode in stable Rust today:

fn main() {
    'foo: for _ in 0..1 {
        println!("break");
        break 'foo;
        println!("broken");
    }
}

So on the one hand, we should just stabilise this because it is barely growing the language, just eliding for _ in 0..1, on the other hand we should not stabilise this because there is an easy way to do it today (for when it is really necessary) and we should not encourage such an anti-pattern be used.

@SoniEx2

This comment has been minimized.

Copy link

SoniEx2 commented Jan 7, 2019

it seems kinda confusing and the label is unnecessary.

breaking blocks is a lot less confusing and requires the label.

I don't understand why you think breaking blocks is an anti-pattern. what applies to X doesn't necessarily apply to not-quite-X. I may be able to buy a computer for $299.99, but not $299.98, even tho they're "basically" the same.

@Centril

This comment has been minimized.

Copy link
Contributor Author

Centril commented Jan 7, 2019

@nrc

I'm not sure if this is an argument in favour of stabilisation or against, but note that this is trivially easy to encode in stable Rust today:

    'foo: for _ in 0..1 {
        break 'foo;
    }

So on the one hand, we should just stabilise this because it is barely growing the language, just eliding for _ in 0..1,

'a: for _ in 0..1 { break 'a } might work if the explicit goal is to not have anyone ever write 'a: { ... break 'a e; ... }; however, it has the drawback of generating garbage IR that the type checker, MIR, and LLVM must process thus worsening compile times (at least in comparison to LBV).

on the other hand we should not stabilise this because there is an easy way to do it today (for when it is really necessary) and we should not encourage such an anti-pattern be used.

I think we disagree that LBV is an anti-pattern. At the end of the day we chose to imbue Rust with imperative control flow rather than just having Rust be a functional programming language. While I might have preferred to not have such control flow, it's fait accompli. The question is then whether LBV is somehow more unreadable or problematic than other imperative mechanisms in Rust. I don't think it is.

While I think that functions should be kept short (vertically) and shallow (indentation), it's better to be long and shallow than long and deep. I find that LBV helps avoid depth in some of the more complicated flows. LBV also seems readable to me as it explicitly denotes where it will jump to, making the flow well understood. All in all, I find LBV to be one of the least problematic imperative control flows.

@SoniEx2

This comment has been minimized.

Copy link

SoniEx2 commented Jan 7, 2019

  1. 'a: for _ in 0..1 { break 'a }
  2. 'a: { ... break 'a e; ... }

these may look similar, but they're not quite the same. while the first is arguably an anti-pattern, the second is arguably not.

kinda like loop {} vs while true {} (granted loop can return a value while while cannot, but let's ignore that for a bit)

@Pauan

This comment has been minimized.

Copy link
Member

Pauan commented Jan 7, 2019

@nrc That doesn't have quite the same behavior though: #48594 (comment)

In particular, the behavior of break; and continue; is different. Consider this hypothetical code:

some_macro! {
   ...
   break;
   ...
}

If some_macro expands to 'a { ... }, that has different behavior than if it expands to 'a: for _ 0..1 { ... }

@cramertj

This comment has been minimized.

Copy link
Member

cramertj commented Jan 7, 2019

@SoniEx2

Has anyone tried rewriting the things in a slower, less-intuitive and less-ergonomic way?

Please try to communicate your concerns in a more positive and productive way. Mocking others doesn't get us anywhere, and makes people feel bad. We're all here because we want to make sure that Rust is the best programming language it can be, and part of that process is ensuring that the community is as positive and encouraging as possible.

@zesterer

This comment has been minimized.

Copy link
Contributor

zesterer commented Jan 7, 2019

Perhaps I'm falling foul of some big misunderstanding. I won't pretend to be an expert in LLVM, Rust's internals, or similar such things. That said, I do have some rudimentary experience with compiler design and I'm confused as to what the concern is. If someone could explain things, I'd really appreciate that.

The way I see things:

  1. This doesn't change the ergonomics of flow control. There already exists constructs like this in Rust such as 'a: loop { if x { break 'a; } break; }.

  2. This doesn't particularly change the ergonomics of block returns: loops are already capable of returning values.

To me, this seems more like the intuitive completion of a set of features that Rust already has - generalizing those features for all (or at least more) blocks.

In terms of concerns about this being too similar to goto, I'm further confused. This doesn't add anything that isn't already possible in Rust, and it doesn't permit backwards jumps (the primary problem that results in poor use of goto regressing into spaghetti code), so I'm failing to understand what ramifications this feature might have in codegen since this seems to effectively be just syntax sugar for an always-breaking loop.

Could anybody explain to me in more specific terms what problems exist?

@cramertj

This comment has been minimized.

Copy link
Member

cramertj commented Jan 7, 2019

Procedurally, IMO it isn't appropriate to file concern blocking or concern should-close-not-merge-style concerns: this concern doesn't list a problem with the feature as-proposed or anything that we could work towards resolving-- it's just a perma-blocker. I don't think that rfcbot's concern mechanism should be used to perma-block features, but only to help track resolution of concerns and make sure that they are addressed / resolved appropriately. My understanding of the process was that the intent was to use an unchecked checkbox to mark your disagreement, and that concerns were to be used to file specific, discuss-able issues about the feature and its functionality.

I could have filed similar "I don't like this" concerns on other features I personally disagreed with (see e.g. uniform_paths), but I don't believe that infinite-filibuster is a productive way to do language design.

If there are specific concerns about the way that this feature interacts with other parts of the language that should be discussed / resolved (e.g. "this seems like it could be obviated by try { ... }" or "it helps to enable un-idiomatically-large functions") I think it would be more productive to file them that way.

@joshtriplett

This comment has been minimized.

Copy link
Member

joshtriplett commented Jan 7, 2019

@cramertj I would not have filed such a concern in that form if @Centril hadn't explicitly suggested it. (I personally would have preferred if FCP had not been proposed.)

What would you suggest as the appropriate process for "this should be closed", if someone has filed a P-FCP with rfcbot for something other than "close"? "make sure that they are addressed / resolved appropriately" sounds equivalent to "this is going to be stabilized one day, what does it take to get there?". That doesn't leave a path in the flow for "this should never be stabilized, this should not be part of the language".

My understanding of the process was that the intent was to use an unchecked checkbox to mark your disagreement

Then we'd need to change the process back to requiring all checkboxes checked to proceed.

I don't believe that infinite-filibuster is a productive way to do language design.

I don't believe it is either. I'd like to find a path to conclude this, too, I just would like to see it concluded in a different direction.

For the record, based on experiences with this RFC, I don't think it's a good idea again to respond to an RFC with a caveat of "we can evaluate/address during stabilization whether we should proceed", because it seems clear to me that doing so produces critical procedural issues like this.

We need a path for saying "yes, I can see how this individual feature would make the language more expressive, but based on overall evaluation of the language, it doesn't carry its weight, and I don't want to further expand the surface area of the language in this way". I believe we need to regularly make that call, lest every proposed feature be seen as inevitable in some form and just a matter of quelling objections and persisting.

@SoniEx2

This comment has been minimized.

Copy link

SoniEx2 commented Jan 7, 2019

I will repeat what I've said before because it seems to have been missed: #48594 (comment)

I basically talked about the differences between using a loop and using a breaking block.

mainly, breaking blocks have different syntax, (slightly) different semantics (with respect to unlabeled break at the very least), they signify different intent, and a few other minor things.

@SoniEx2

This comment has been minimized.

Copy link

SoniEx2 commented Jan 7, 2019

does rfcbot support anticoncerns?

@cramertj

This comment has been minimized.

Copy link
Member

cramertj commented Jan 8, 2019

@joshtriplett

We need a path for saying "yes, I can see how this individual feature would make the language more expressive, but based on overall evaluation of the language, it doesn't carry its weight, and I don't want to further expand the surface area of the language in this way". I believe we need to regularly make that call, lest every proposed feature be seen as inevitable in some form and just a matter of quelling objections and persisting.

Yeah, it's an unfortunate hazard of our current process that either accepting or rejecting a feature require full consensus of the appropriate team. When the lang team is as large as it is now, it's difficult to always achieve this-- I thought from the comments above that this was just missing code examples to motivate why this feature is important, but it now sounds like you agree that there is code that can be better written using this feature, but aren't convinced that it is worth the costs you see here. I'm not sure of a way to convince you that these cases are sufficient motivation, as it seems like continuing to provide examples (including the macro example, which is literally impossible to write in another style) isn't enough.

Similarly, I'm fairly confident that I personally will remain convinced that this feature should be merged: IMO it not only pulls its weight through a variety of examples where it is the best/only option, but the language is actually simpler with its addition (since not allowing labelled blocks is surprising to me given that we allow other labeled constructs).

If you agree with my above summary of your position, then it seems we're at an unfortunate (and, I believe, historic!) impass lacking a process. One option is to intepret the current rfcbot rules as I did above to mean "no checkbox signals your disagreement, three members are necessary to overrule the majority", but I don't think that's how the rules were meant when they were introduced, so I think it was disingenuous of me to suggest that you should follow this procedure (though I did it myself elsewhere).

I've previously heard suggestions that we could introduce a time limit for features going from approved->implemented->stabilized, and that we should "auto-close" features which fall behind in an effort to avoid an ever-increasing backlog. Something like that could address this case, where I (and, I think, several others on the team) will not mark checkboxes to close, nor will you mark a checkbox to accept (I still even now feel afraid even saying this that I'm throwing away a last-ditch effort to convince you! 😄).

I worry that with ever-growing teams we'll lose the ability to come to consensus on features, and that it will be hard to steer the language in a coherent fashion, particularly on the lang-design team. Team size limits seems like an obvious solution to this-- it's possible to receive input from a large number of people, but quite impossible to build absolute consensus among a sufficiently large group. Others will probably argue that contentious features shouldn't be merged in an effort to safeguard the language from misfeatures. I personally think the community is unlikely to let us make to many of those mistakes without adequate warning, but it's a thought.

I'll try and start a separate thread to discuss the process evolution here, and in the meantime I'd ask that folks chiming in on this thread please only post if there are new, critical use-cases to consider that are notably different from those above, or if there is a significant unconsidered reason why this feature should not be added to the language. Reading through the whole history on these megathreads is difficult, but it becomes even more-so when posts are repeated over-and-over, or when the thread is filled with unhelpful commentary. (he says having now typed one of the longest comment sin the whole thread XD)

TL;DR: I think we're stuck, we should have a process for this-- I'll start that conversation elsewhere and link it here. Otherwise, please don't comment unless you have significant new information that needs to be considered.

@joshtriplett

This comment has been minimized.

Copy link
Member

joshtriplett commented Jan 8, 2019

@cramertj

it's an unfortunate hazard of our current process that either accepting or rejecting a feature require full consensus of the appropriate team

I would honestly consider that a feature.

I thought from the comments above that this was just missing code examples to motivate why this feature is important, but it now sounds like you agree that there is code that can be better written using this feature, but aren't convinced that it is worth the costs you see here.

I still feel that many of the examples could be written in other ways. This does not add any unrepresentable expressiveness to the language. I originally felt that it could be motivated with sufficient examples, but the more examples I see that could use this feature, the more I find myself agreeing with @withoutboats that this feature simply shouldn't go into the language.

(Also worth noting: @nrc's crate proc-macro-rules that used label_break_value seems to have been rewritten to avoid it.)

One option is to intepret the current rfcbot rules as I did above to mean "no checkbox signals your disagreement, three members are necessary to overrule the majority", but I don't think that's how the rules were meant when they were introduced, so I think it was disingenuous of me to suggest that you should follow this procedure (though I did it myself elsewhere).

I do think that's the correct procedure for "abstaining", but not for objecting.

IMO it not only pulls its weight through a variety of examples where it is the best/only option, but the language is actually simpler with its addition (since not allowing labelled blocks is surprising to me given that we allow other labeled constructs).

I do typically find orthogonality arguments compelling, but this one in particular I find uncompelling, as personally I would have preferred not to have labeled loop breaks in the language either.

I worry that with ever-growing teams we'll lose the ability to come to consensus on features, and that it will be hard to steer the language in a coherent fashion, particularly on the lang-design team.

I worry not just about steering but about stopping. There's a certain inevitability that crops up sometimes, where the process seems focused on finding a path to "yes" and there's no graph edge in the flowchart that leads to "no", just "not yet".

There have been many posts written in 2018 and 2019 talking about feature growth in the language, and I feel that in the language team we need to give serious consideration to the total surface area of the language. And I feel like we don't have good processes that encourage us to do that.

@cramertj

This comment has been minimized.

Copy link
Member

cramertj commented Jan 8, 2019

@joshtriplett

This does not add any unrepresentable expressiveness to the language.

To be very clear: it does do exactly this. There is currently no way to express this code that does not interfere with other control-flow constructs, which (as others have pointed out) is especially desirable in macros, where this would be the only construct which is untargetable via un-labeled breaks, allowing macro-authors to break from sections without risking an overlap with a user-provided break.

@SoniEx2

This comment has been minimized.

Copy link

SoniEx2 commented Jan 8, 2019

it also makes code more readable as you don't have to zig-zag around (if we had no labels at all - see Lua example) or do weird stuff with loops. this also has a small performance benefit even tho llvm should be able to optimize zigzag code.

@Centril

This comment has been minimized.

Copy link
Contributor Author

Centril commented Jan 8, 2019

@joshtriplett

I still feel that many of the examples could be written in other ways. This does not add any unrepresentable expressiveness to the language. I originally felt that it could be motivated with sufficient examples, but the more examples I see that could use this feature, the more I find myself agreeing with @withoutboats that this feature simply shouldn't go into the language.

Is that something we could dig into perhaps?

I do typically find orthogonality arguments compelling, but this one in particular I find uncompelling, as personally I would have preferred not to have labeled loop breaks in the language either.

This line of reasoning I find strange (unless you wish to remove labeled loop breaks with an edition). It does not seem appropriate to base design decisions based on what you wished weren't in the language. It is there, and so we should consider whether this addition is coherent with that. Otherwise there are many things I might have done differently about Rust, but I should not and cannot.

I worry not just about steering but about stopping. There's a certain inevitability that crops up sometimes, where the process seems focused on finding a path to "yes" and there's no graph edge in the flowchart that leads to "no", just "not yet".

Not yet is its own form of "no" in the sense that it won't get stabilized without a yes. Furthermore, there is a no: convince the rest of us that LBV is a bad idea / not sufficiently motivated for X, Y, and Z reasons. I have yet to hear many such concrete arguments at all. You have also demonstrated clearly here that there is no inevitability.

There have been many posts written in 2018 and 2019 talking about feature growth in the language, and I feel that in the language team we need to give serious consideration to the total surface area of the language. And I feel like we don't have good processes that encourage us to do that.

I personally feel that many of these posts are either about sustainability (but not as aptly worded as @nikomatsakis did...) or that many folks don't understand how the language team operates (i.e. we already do give serious consideration to the total surface area). The total surface syntax of Rust has probably actually shrunk over the last year, not grown. LBV doesn't increase that notably and an argument could be made that it actually shrinks the number of productions in the language and makes the syntax more uniform.

@rpjohnst

This comment has been minimized.

Copy link
Contributor

rpjohnst commented Jan 8, 2019

Merely combining grammar productions does not shrink the surface area of the language.

@SoniEx2

This comment has been minimized.

Copy link

SoniEx2 commented Jan 8, 2019

Reducing the number of conditional branches one can take is arguably shrinking the language's surface area.

I don't think this particular feature goes either way, as such it's probably neutral. But e.g. things that unify language constructs (bool let, anyone?) do shrink surface area.

@traviscross

This comment has been minimized.

Copy link

traviscross commented Jan 11, 2019

For what it's worth, Common Lisp, which is similar to Rust in the sense that it's a multi-paradigm language with macros, has this feature (named block / return-from). Similar to what has been discussed here, in Common Lisp this construct is often helpful when writing macros and in expressing irreducibly complex control flow.

(block foo
  (return-from foo "value"))

My sense is that in Common Lisp this feature is considered successful. It doesn't come up in conversations about features that make the language difficult to learn or implement.

@JohnBSmith

This comment has been minimized.

Copy link

JohnBSmith commented Jan 12, 2019

There is the inclusion

early return from block ⊂ exceptions ⊂ call/cc

For example, in Scheme the following emulation of return-from is feasible:

(define call/cc call-with-current-continuation)

(define-syntax block
    (syntax-rules ()
        ((_ label statements ...)
            (call/cc (lambda (label) (begin statements ...))))))

(block foo
    (display "Visible text")
    (foo "value")
    (display "Phantom text"))

In Scheme, call/cc is seen as successful as controversial. I find this particularly interesting because you first have to formulate an object in order to be able to talk about it. Even if you consider call/cc as a misfeature, it made the language more substantial in an intellectual sense.

@NN---

This comment has been minimized.

Copy link

NN--- commented Mar 3, 2019

Nemerle language has Named blocks functionality.
It is very useful and convenient.

return, break and continue are implemented as macros using this feature.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
You can’t perform that action at this time.