Hi Steve,
> Thanks for the responses! I will look into using the 'state' for the
> iterator that can be later dereferenced. Indeed, one has to be careful
> that the iterator could point to a data item that has been changed or
> deleted. In C++, for each container operation there is a specification of
> whether iterators are invalidated by the operation.
In Julia the convention is that there is no guarantee that it's safe to
change the collection whilst you're iterating over it (Python does the same, I
think).
Then, from the rest of your email, I'm not sure whether you are aware
that the user will almost never call start, next and done. For example
to iterate over the keys of an ordinary dictionary:
for k in keys(mydict)
...
end
Or here an example on making a new array iterator:
import Base:start, next, done
immutable EvenIt
ar::Vector
end
# (state needn't be the index)
start(ri::EvenIt) = 1
next(ri::EvenIt, state) = (ri.ar[2*state], state+1)
done(ri::EvenIt, state) = 2*state>length(ri.ar)
# convenience user-function
eveniter(ar::Vector) = EvenIt(ar)
# user usage:
for e in eveniter(ar)
println(e)
end
> As for multiple ways to index, the example I have in mind is as follows: if
> m is the associative map, (k,v) is a key-value pair, and i is an iterator
> (the pointer kind, like in C++) to (k,v), then m[k] should return v, while
> m[i] should return (k,v). But I am asking the forum whether a distinctive
> syntax is available for the second variant.
So, I'm not sure the need for a second way of indexing for what you want
to do here. (However, it could be a neat thing to do at times. For
your use case it may be nice to use the normal `m[key]` as well as
`m<i>` to get item at index i. The other case which comes to mind are
Fortran co-arrays, where one index is a normal array index and the other
indexes the processor on which the array is located.)
> Finally, with regard to the third issue, perhaps I didn't express my
> question well. Suppose someone uses my 2-3 trees and has a statement in
> his/her code such as
> i = next(m,i)
> where m is the map and i is an iterator (of the pointer kind). This
> statement is supposed to advance to the next item according to the
> sort-order of keys. My routine that gets invoked is as follows:
>
> function nextloc{K,D}(t::BalancedTree{K,D}, i::Int)
> if i == 2
> error("Attempt to advance past end of balanced tree")
> end
> ii = i
> p = t.data[i].parent
> while true
> newp, newii = nextloc0(t, p, ii)
> if newii == 2 || t.data[newii].parent > 0
> return newii
> end
> p, ii = newp, newii
> end
> end
>
> Now, suppose instead the user writes:
>
> @inbounds i = next(m,i)
>
> Then I would want a different (faster, less safe) version of 'nextloc'
> invoked. In the different version, the preliminary safety-test whether
> i==2 is omitted, and the array subscript operations within my code are all
> prefixed by @inbounds. So my question to the forum is whether my tree code
> can detect whether the user has put an @inbounds declaration in his/her
> code when it invokes my routines.
The `done` function should make sure that `next` is never called with a
`state` out of bounds (see my example above). In fact, this is the sole
purpose of `done`. So, no need for checking in next.
> Thanks,
> Steve
>
>
> P.S. If you want to look at my code, please
> see: https://www.dropbox.com/s/021yc196j55d5yd/baltree.jl[1] This code is
> very preliminary and has not even been executed, except for insert and
> next. (See the test routine test2(), which seems to work.) The 'delete'
> code is currently a hack, and I need to write a proper delete code that
> shrinks the tree.
Having had a very brief look at your code. I think the
iterator-helper-type usually just wraps the thing it wants to iterate as
I did in above example. The `state` variable is then what you have as
`address` in your MapIterator.