Iterators on Julia 0.7 (and announcing the Invenia blog)

blog

#1

In this post I talk about the new interface and share some tips and useful patterns for dealing with iteration in Julia 0.7:

It’s been shared on Hacker News, if you feel like upvoting.

This also serves as the announcement of the Invenia technical blog, which will see more posts about Julia, machine learning, and electrical grids. Check out Eric Perim’s two-part post on our SyntheticGrids.jl package:



#2

Nice post! I learned a couple of good tips from it.

In your “Slurping and Splatting” section, given that the docstring for iterate does not discuss multiple state arguments, I do wonder a bit about the wisdom of creating a varargs iterate—in my initial glance at the code, I wondered if it could be like getindex and it might be of variable lengths maxing out at iter.interval.

Here’s an alternative, where I pass an extra count element indicating how many items are left:

function iterate(it::TakeNth)
    xs_iter = @ifsomething iterate(it.xs)
    return iterate(it, (it.interval-1, xs_iter))  # we already consumed 1 item, so count=it.interval-1
end

function iterate(it::TakeNth, (count, xs_iter))
    for i = 1:count
        xs_iter = @ifsomething iterate(it.xs, xs_iter[2])
    end
    return (xs_iter[1], (it.interval, xs_iter))   # next time, start over at the full count = it.interval
end

Admittedly it’s slightly more complicated, but aside from not making a questionable method this does have benefits:

master:

julia> using IterTools

julia> tn2 = takenth(10:20, 3)
IterTools.TakeNth{UnitRange{Int64}}(10:20, 0x0000000000000003)

julia> returnstrue(x) = true
returnstrue (generic function with 1 method)

julia> count(returnstrue, tn2)
3

julia> using BenchmarkTools

julia> @btime count($returnstrue, $tn2)
  273.126 ns (12 allocations: 352 bytes)
3

This implementation:


julia> @btime count($returnstrue, $tn2)
  37.008 ns (1 allocation: 32 bytes)
3

Also, one small correction regarding Base.tail:

No matter the size of the input tuple, it will always return at least an empty tuple.

That’s true except for an empty tuple, which triggers an error. (which is a good thing)