Joachim
Joachim

Reputation: 590

How to implement an iterator in Julia?

I am trying to implement an iterator in Julia, but get an exception when the for-loop tries to call start already.

Here is what I get (I ran include(...), then using RDF):

julia> methods(start)
# 1 method for generic function "start":
start(graph::Graph) at /Users/jbaran/src/RDF.jl/src/RDF.jl:214

julia> for x in g
       println(x)
       end
ERROR: `start` has no method matching start(::Graph)
 in anonymous at no file

The function definition in the RDF module looks like this at the moment:

function start(graph::Graph)
    return GraphIterator(collect(keys(graph.statements)), nothing, nothing, nothing, [], [])
end

Any idea what I am doing wrong?

Upvotes: 8

Views: 7588

Answers (3)

Ben
Ben

Reputation: 105

Building off of @BoZenKhaa's answer, a common pattern is

Base.iterate(yt::YourType, state=1) = state > length(yt) ? nothing : (yt.data[state],state+1)

where YourType has a field data which can be indexed as an array, with state holding the index. Along with state=1, the right hand side uses the ternary operator to combine lines 1+2, returning nothing if at the end or if in bounds a tuple of the element at that state and the next state.

Upvotes: 4

BoZenKhaa
BoZenKhaa

Reputation: 951

In Julia 1.+, you should implement:

  1. Base.iterate(::YourType) for the starting iteration,
  2. Base.iterate(::YourType, state) for following iterations while getting the state from the previous steps.

Both methods should return (result, state) tuple, except for the last iteration that should return nothing.

In practice, this means that iterating on x::YourType with

for i in x
    # some code
end

is a shorthand for writing

it = iterate(x)
while it !== nothing
    i, state = it
    # some code
    it = iterate(x, state)
end

See the manual for details.

Upvotes: 13

IainDunning
IainDunning

Reputation: 11664

Don't forget to specify Base. - you are adding methods to an existing function.

module MyMod
  type Blah
    data
  end
  export Blah
  Base.start(b::Blah) = 1
  Base.done(b::Blah,state) = length(b.data) == state-1
  Base.next(b::Blah,state) = b.data[state], state+1
end
using MyMod
x = Blah([1,2,3])
for i in x
  println(i)
end

This works as of Julia 0.3.

Upvotes: 9

Related Questions