4
votes

Iteration in Julia can be achieved for a new defined type by implementing the iteration interface that has the 3 functions: start, next, done

I see no exclamation point on the end of those functions so from my understanding of julia naming conventions these 3 functions should not modify their arguments. In particular these two loops should give the same output

state = start(iter)
while !done(iter, state)
    (i, state) = next(iter, state)
    @show i
end


state = start(iter)
while !done(iter, state)
    (other_i, other_state) = next(iter, state)
    (i, state) = next(iter, state)
    @show i
end

Am I wrong? I ask because I bumped into some iterators in external julia packages not respecting this.

2
In general iterators should be immutable anyway, as altering the contents during an iteration is dangerous business, so it wouldn't make sense to use a mutating function on them. As for mutating state, I suppose there's no ! in the name because even though in theory the next function could mutate the received state object and simply return it again, rather than just returning a new state object, in practice the state object is not supposed to be manipulated directly, but is meant to be internal to the for statement, as is next. So presumably lack of ! is just for consistency. - Tasos Papastylianou
Which package was it you spotted the "disrespectful behaviour"? :p - Tasos Papastylianou
Thanks for your clarification @TasosPapastylianou. Don't worry about the package, it will be fixed. - Issam T.
oh, I'm not saying there's anything that necessarily needs fixing per se. Mutating the intrinsic state variable isn't a big deal (might even be a more efficient way of implementing an iterator). I was just curious where you saw it so I could have a look :D - Tasos Papastylianou
For anyone coming across this question with Julia 1+, iterators are implemented differently, see the manual or for example this question: stackoverflow.com/questions/25028539/… - BoZenKhaa

2 Answers

7
votes

If possible, those functions are not supposed to mutate the iterator (such that the iterator state can be copied and re-used). However, there are some prominent examples where such a design is not possible, or only possible with significant performance penalties. The prime example of this is Base.Task, which is iterable (each iteration running until the next produce statement):

julia> collect(@async for i = 1:10
       produce(i)
       end)
10-element Array{Int64,1}:
 1
 2
 3
 4
 5
 6
 7
 8
 9
10

In those cases we've generally been fine with mutation (though of course any use of the iteration protocol that caches states won't work). The exclamation point at the end of functions is a convention, but is not enforced in any way (and is not strictly limited to mutation of its input arguments, but rather having some side effect that you want to make sure the programmer is aware of).

3
votes

Those methods should not modify their arguments, probably because you may want to re-use an iterator, and you're right about the exclamation mark.

And you are right, the custom is to append ! to method names if they modify their arguments

I've also come across a package, the ProgressMeter package which uses the method next!() and that one does change the progress-meter type that you have

I like the idea of the exclamation mark (I don't know if it originated in Julia or elsewhere) but surely its important for developers to be consistent with this

tl;dr You are right, it says so in the docs, and to really cement the point, the section detailing it is called Essentials

(note to non-native English speakers, there is no such thing as an exclamation point)