-
Notifications
You must be signed in to change notification settings - Fork 13.4k
support break and continue in blocks via enums #1619
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
Comments
I forgot to write how this would be used. Iteration primitives which support break and continue, such as
|
In languages with methods or functions and blocks as distinct features, the Tennent's Correspondence Principle way to handle 'ret' would be that it forces return from the nearest enclosing non-block. This is what Smalltalk had, Ruby too, and my http://wiki.ecmascript.org/doku.php?id=strawman:block_lambda_revival proposal for JS does likewise. Is this out because we want blocks to be fn-like with regard to 'ret'? /be |
So, TCP is why I said we'd just disallow ret. It's out (at the moment) because compiling it requires either some sort of forced unwinding (slow) or else inserting magic plumbing such that a call to What I mean is, if we just added |
What's weird is that when I first started using Smalltalk I found it very surprising that |
Yeah. We've been round and round on this many times. Definitely supporting TCP for So .. short story: I'm ok with just trying for But taking a lesson from scheme .. with what you're proposing here, it still feels a bit overdone for the compiler to know about a core |
I personally favor having a more intentional type like loop_ctl than a plain boolean, though a newtype'd boolean would be ok. One reason I would like to add compiler sugar is that I think all of the loops which are now of type fn(A) ought to be breakable (e.g., vec::iter()). If the loop body is inlined this ought to be zero-overhead as well. |
Basically the basic "iterable" type (as defined in the iter module) would change from |
I'm fine with that aspect of it ( |
I guess it's a matter of taste. I always found the use of But there is one concrete issue with using bool: in that case, the compiler cannot help at all, which means that if we try to use loop_ctl ubiquitously, then every loop will look like:
which doesn't really strike me as a good idea. Of course you didn't want the compiler to help, which is fine too, but it strikes me that then we will always want to have two iteration primitives: one that always continues and one that may break. We could make this less painful with traits, so that for a given type you need only define the breakable iterator and the "always continue" comes for free, but it still means two iteration methods:
vs
(Or we could re-use the Well, there are two or three possibilities. I guess in the end I don't care that much. Maybe I'll draw up them up in more detail with some examples and send out an mail to see what other people find most appealing, since this is ultimately an ergonomics issue more than anything. |
I'm in favour of mild compiler magic here (supporting |
@nikomatsakis So judging by your e-mails and irc messages, you seem to be working on this. Should I assign back to you? Or shall I implement my understanding of what you have planned? |
(Significant followup on this in email: https://mail.mozilla.org/pipermail/rust-dev/2012-February/001432.html ) |
The last argument of the call must be a block, and the type of this argument must a function returning bool. `break` and `cont` are supported in the body of the block, and return `false` or `true` from the function. When the end of the function is reached, `true` is implicitly returned. for vec::all([1, 2, 3]) {|elt| if elt == 2 { break; } log(error, elt); } Issue #1619
For use with the new for construct. Issue #1619
marijn's commits (listed above) implemented this---something better, as a matter of fact. |
This is done. |
Most could use the each method, but because of the hack used to disambiguate old- and new-style loops, some had to use vec::each. (This hack will go away soon.) Issue #1619
This replaces link to a removed lint with a link to discussion of lints of its type.
This replaces link to a removed lint with a link to discussion of lints of its type.
So, I like the idea of supporting
break
andcont
(and, ideally,ret
) within blocks but I am not sure how they ought to be implemented. In particular, I don't like the idea of the compiler magically inserting code around block calls to handle non-local returns. Therefore, I am throwing out this half-way scheme to see what people think. It does not allowret
within blocks but it does allowbreak
andcont
and involves relatively little magic.The idea is to create a "well-known" enum in the core library:
Within a sugared closure,
break
andcont
would be equivalent toret lc_break
andret lc_cont
. Next, if there is no existing tail expression in the sugared closure and the expected return type isloop_ctl
, the tail expressionlc_cont
is added by default. Finally, we disallow explicit use ofret
within sugared closures all together, because it is potentially confusing and (besides) hurts our current type inference.The final condition is not needed. We could keep
ret
with the current meaning of "return from the closure early" and just fix up the type inference algorithm. I am somewhat indifferent but I do think it's mildly confusing, particularly ifbreak
andcont
start to work.The text was updated successfully, but these errors were encountered: