I was just wondering what thoughts people have on the following syntax
for iter if cond
#stuff here
end
which would basically be short for
for iter
if cond
#stuff here
end
end
Obviously this isn’t necessary, but I don’t think it would hurt and it should be intuitive and “julian” since we already have this sort of thing for comprehensions, where something like [i for i = 1:10 if i%2 == 0] will return [2,4,6,8,10].
Language design can of course be very subjective, but I think that adding basic syntax that is not necessary for a special case of something we already have is as anti-Julian as it gets.
We have perfectly fine, composable control flow building blocks for this purpose already. Alternatives include
Personally, I think making for loops mirror comprehensions is pretty Julian. If we follow your logic, we should get rid of the conditional in the comprehension syntax.
[f(i) for iter if cond(i)]
doesn’t do anything that we can’t achieve with using filter or boolean indexing.
Aren’t comprehensions just shortcuts for writing a loop anyway? Maybe cut them out all together.
Neither is not a good comparison. Using the [... for ... in ... if ...] syntax avoids creating temporaries for the unfiltered interim results, boolean indexing OTOH would require them. filter operates on existing iterators, the comprehension syntax creates iterators and collects them; a pretty common use case.
The point is not to avoid any kind of parallel solution — that neither desirable nor practical — but to have a small number of orthogonal building blocks that combine well. For this particular purpose, control flow already works very well.
On a somewhat related note, I admire how clean Julia is from a control flow perspective. Basic (non-coroutine) control flow has combounding (begin, ( ; )), two kinds of loops (for, while), branching and short-circuiting boolean ops, and the standard exception handling constructs. And that’s it! We can build the rest easily from these components. (Technically for is redundant once we have while, but it meshes so well with iteration that it is worth it).
Another cute option (not sure about it keeping full performance):
julia> If(cond) = Base.Fix1(Iterators.filter, cond)
If (generic function with 1 method)
julia> for i in 1:10 |> If(iseven)
@show i
end
i = 2
i = 4
i = 6
i = 8
i = 10
I didn’t quite follow this part - what’s different about for loops, compared to comprehensions, that would necessitate creating temporary values for interim results?
FWIW I (a relative Julia newcomer) just found this conversation after expecting the for ... if ... syntax to work, since it already works in comprehensions.
It’s the other way around. Comprehensions inherently allocate arrays, for loops do not. In the former case (comprehensions), it’s useful to provide an if statement as part of the syntax, so that you don’t allocate an array bigger than necessary. In the latter case (for loops), there is no need for a special syntax, since you can just put an ordinary if statement in the loop body.
Also, the argument to a comprehension is just a generator expression, and generator expressions can be used anywhere an iterator is allowed — including comprehensions, function arguments, and for loops. e.g.:
julia> sum(i for i = 1:10 if i%2 == 0) # == sum([2, 4, 6, 8, 10])
30
julia> for i in (i for i = 1:10 if i%2 == 0)
@show i
end
i = 2
i = 4
i = 6
i = 8
i = 10