I have found myself wanting to write something like:
X = [f(a) for a in iterator if cond1(a) while cond2(a)]
and have this return elements from the iterator until cond2(a)
returns false. This would essentially be the same as:
X = []
for a in iterator
!cond2(a) && break
cond1(a) && push!(X, f(a))
end
Using while
in this context looks and feels a lot like the functional takewhile
function, uses an already existing keyword, and is to my eyes a lot less noisy than the explicit loop above.
There are a few StackOverflow questions that have asked for a similar functionality here https://stackoverflow.com/questions/44097910/killing-a-for-loop-in-julia-array-comprehension and here https://stackoverflow.com/questions/44101965/array-comprehension-with-a-random-output-in-julia/
Could be added as a feature in the 1.x series since it's a syntax error currently.
Shouldn't this rather be written [f(a) for a in iterator while cond2(a) if cond1(a)]
, to be consistent with the usual ordering?
I have no real inclination one way or the other, but I thought the sentence "get item from shop if item is in shopping list while wallet is not empty" sounded better than "get item from shop while wallet is not empty if item is in shopping list".
But if this is implemented, it would also make sense to extend it to
for a in iterator while cond(a)
...
end
and here it's more clear the if
should come after the while
.
How would you know that the while
isn't a while loop in the explicit loop case? But I like the idea of extending it, although it doesn't do much except save a line and two characters from cond(a) && break
. 馃槃
Well, the syntax would be defined so that it can't be a while loop unless there's a new line. You're right that that would be quite confusing though.
I'm not entirely opposed to the notation for arbitrary loops, but I do think it would cause head scratching for most people on the first read. Going a bit further, and I'm really not sure if I like this idea myself, but if it translated into a return a
instead of break
, you could write dropuntil
as:
x = for a in iterable while cond(a) end
->
x = for a in iterable
!cond(a) && return a
end
which has a nice symmetric similarity with the proposed comprehension syntax of takewhile
.
Any occurrence of while
in a comprehension or loop context will cause head-scratching since it has no precedence in other languages.
A good first step would be to add the appropriate Base.Iterators.takewhile
function, which will be needed to implement the comprehension with anyway. The takewhile
can be used in more situations because it's more general.
It's worth noting that comprehensions already support more syntax than ordinary for loops in that they can have condition clauses, which for loops cannot. I don't think it makes sense to couple adding features to comprehensions with adding them to for loops since these things are already easy to express with for loops by using break
and continue
.
Most helpful comment
I have no real inclination one way or the other, but I thought the sentence "get item from shop if item is in shopping list while wallet is not empty" sounded better than "get item from shop while wallet is not empty if item is in shopping list".