-
-
Notifications
You must be signed in to change notification settings - Fork 5.5k
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
for-else and while-else #1289
Comments
Bump. Can this be 0.4? |
I guess you've decided on this behavior—just thought I'd pipe in with an opinion. I find Python's behavior really useful here, where the |
That Python for-else behavior has always struck me as very unintuitive, honestly. Mostly it's the name, not the functionality itself. The functionality can be emulated with gotos, but it is kind of awkward. |
Whilst there is nothing against this, at least in my experience the thing that is needed most often is to know if the loop was But I have never found a "nice" way of specifying the required combination(s) of the three conditions, that the loop never ran, shortcut (break), or completed. |
Yeah, @StefanKarpinski, I guess it's mainly a matter of recycling keywords in Python. I think the naming is less awkward/surprising for |
Two different suggestions for what one rarely used syntax should mean, seems like a bad sign. |
Well, one would never guess at the Python meaning without already knowing it, whereas I think the meaning of executing if the main body never executes is pretty intuitive, but yes, that's still a point. |
I know that it's a keyword not yet used on Julia, but I feel that the |
Actually, @StefanKarpinski, I hadn't noticed there were gotos in Julia; saw them in the |
This is a super useful feature. Has a resolution for this been decided or is everyone going to use goto? |
using @goto will trigger a lint warning, fyi. |
@tonyhffong Why? |
er, I thought the whole point of for-loop and while-loop is to minimize the use of goto. Julia allows goto, that's fine, lint.jl doesn't have have a big-boy assumption. |
TL;DR; I think an unconditional warning about goto/label belongs in a style checker, not in a linter. I thought the point of the higher level constructs was to be able to express most code in a clearer more readable way. We had a thorough discussion before adding |
I would say that people are much more likely to do something like this:
than this:
for/else and while/else are the natural and obvious solution, even if you rename the else clause. I saw a talk from a core python dev who wished they'd named "else" to be "nobreak". If we're so concerned about naming, perhaps nobreak is a good name. At least it's descriptive. (But for/else actually has a history in CS so it shouldn't really be so surprising to people...) |
@ivarne it's a grey area no? We judge "poor style" being one that can be prone to logical error. So where is the line between "prone to error" (lint ok) and "suspicious usage" (lint not ok)? Of course goto is not suspicious unconditionally, so are many current lint warnings, such as declaring an unused variable, dead branch, empty literal range [1:0]. This criterion seems inadequate. There's always judgment involved. Well currently it's mine, but it could be changed. How about this, I could add lintpragma to silence the goto lint messages (btw, the current message is only at the INFO level, not at the higher WARN/ ERROR/ FATAL levels). Do you consider this meeting half-way? |
The discussion about lint and Please continue the |
I prefer Python's behavior too. It's the one I use most often. |
I think the This feature is quite helpful in Python, and I would love to see it in Julia, as well. 🙂 |
Is there actually precedent for this construct in any language besides Python? |
IMHO for-then-otherwise could be better than for-else because it is more complete and won't create confusion for pythonistas. I propose also thinking about other use of for. For example: [i for i in A then in B otherwise in C] But I understand that then there could be questions/complications: # what if cond(i) is false for every i in A? Does it invoke otherwise clause?
[i for i in A if cond(i) then in B otherwise in C]
# inner loop only after then/otherwise?
[z for i in A then in B otherwise in C for z in [7*i] ] |
I know I'm reviving a super old thread, but I have been really missing this kind of syntax recently. What do people think about using the word "finally" ? Code in the finally clause executes if the loop ends successfully, and not if the loop is broken out of. Its not 100% in line with the use in a try-finally context, but I think the word still makes sense, and would be appreciated by people used to the while-else syntax. |
To be honest I no longer miss the See also #22891 for a more complete proposal. However, in response to that thread, I would say that a function is perfectly fine for this (I post here to not revive that old thread):
So, is there any good reason to add this feature? Like any real use case where it would really simplify code? |
I written a fair amount of code recently that could really use the for else feature. |
I've found myself wanting this recently as well. |
If you'll indulge me for a moment recapping this feature from my point of view, I can possibly add a note about scope. All loop exits but the normal one have "instructions on exit" expressiveness, due to the embedded nature of
...where I've used stand-in keyword Which is a quite general bit of control flow to leave out of a language. Besides the obvious expressivity gain that Python gains from too, avoiding the need for boolean flags / other workarounds as usual for an omitted control flow structure, in Julia there is one further privilege of exiting instructions that is not expressible beyond the loop: loop scope. Thus even in a loop absent any Am I mistaken? This makes keyword Unfortunately, As an aside, if one really wanted to, As to the painful situation of not obtaining the While finishing 1.0 the devs chose to kick the can on this til 2.0. Now we live with the wait. (Or in the meantime, are tempted to expropriate Quick question @StefanKarpinski, I believe your most recent post refers to Python's meaning of else (and not to your OP meaning). If this github issue is now dedicated to that feature and not to the OP, including for milestoning, would you find it advisable to change the title to match? (Which is not characterized by |
I'm not following what you're saying here about scope. Can you give an example to illustrate?
Yes, we're only considering the Python-like meaning at this point. The title seems to still be accurate, however, since the feature is applicable to both for and while loops as far as I can tell.
for-else is currently a syntax error, so there's no need to wait until 2.0 for this feature. I find the statement of how hard it is to live without this feature a bit overstated. Many languages, including C, C++, Java and JavaScript have gotten by without this for their entire existence and even become respectably popular. |
Thanks, I guess I should've given an example. Consider finding and storing the largest power of 2 less than a million. One might write
(We could divide the final n by 2 instead of what's done here, but in an analogous example that might not be possible.) Keyword I don't mean to suggest there aren't alternatives to the coding approach here; but rather, I mean this is a reasonable usage of the features of Julia once the new feature is adopted. So we can expect its use. A keyword along the lines of
I was actually not referring to your use of But no worries about the title, it's a title.
Acknowledged. Apologies for overstating this. |
Just wanted to point out that @StefanKarpinski's proposal is not inconsistent with the Python sense of for-else and while-else. For example (note how In [1]: for i in range(3):
...: print(f'in loop. i = {i}')
...: else:
...: print('in else')
...:
in loop. i = 0
in loop. i = 1
in loop. i = 2
in else
In [2]: for i in range(3):
...: print(f'in loop. i = {i}')
...: break
...: else:
...: print('in else')
...:
in loop. i = 0
In [3]: for i in range(0):
...: print(f'in loop. i = {i}')
...: break
...: else:
...: print('in else')
...:
in else By adopting the python sense of for-else and while-else (or whatever |
That depends on how you read the proposal. At least to me,
seems to be using a definitional if (see, e.g., p. 123 here), i.e., to define an I still regularly need the Python version (and have never so far needed the one suggested here) … but that's life :-} |
This adopts the semantics discussed in #1289, namely the `else` block is executed whenever the loop never runs. Unlike Python, `break` and `continue` are irrelevant. Multidimensional loops are not supported since there is some ambiguity whether e.g. ```julia for i in 1:3, j in 1:0 print(1) else print(2) end ``` should print 2 once, thrice or maybe not even at all. Currently only supported in the flisp parser, so requires `JULIA_USE_FLISP_PARSER=1`. I could use some guidance on the necessary steps to add this to JuliaSyntax as well - AFAIU this would also require #56110 first. closes #1289
Allow and else clause on for and while loops that executes if the loop never executes.
The text was updated successfully, but these errors were encountered: