-
Notifications
You must be signed in to change notification settings - Fork 262
use standard iterator for Stack + Queue Fixes #116 #171
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
use standard iterator for Stack + Queue Fixes #116 #171
Conversation
|
Okay, seems mostly reasonable to me. Because the If you haven't yet, look at the discussion in #116 (which probably could be closed). That's discussion is the reason that the interface is the way it is now. I think if we're going to go the route suggested there, it should be planned out better ( Cc: @lindahua @RaviMohan |
|
(And of course, you noted that this fixes #116 in this PR, so you obviously saw that...) Anyway, thanks for the PR! |
|
@kmsquire I saw the discussion there, though I think I was wrong in removing the |
|
I think that sounds good. I wouldn't copy the
|
8361f4d to
4f033a3
Compare
|
@kmsquire let me know what you think of this - I ended up using |
e3978ed to
aa95e77
Compare
|
Hi @rawls238, unfortunately, while it seems elegant, using julia> y
DataStructures.Stack{Int64}(Deque [[28,83,82,77,61,53,17,13,73,51]])
julia> [i for i in forward_iter(y)]
ERROR: MethodError: `length` has no method matching length(::Task)
in anonymous at no fileSince a I'll add a few other comments inline. |
src/DataStructures.jl
Outdated
|
|
||
| export Deque, Stack, Queue | ||
| export deque, enqueue!, dequeue!, update!,iter | ||
| export deque, enqueue!, dequeue!, update!, forward_iter, backward_iter |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
In other areas of julia, reverse is used instead of backward. While backward isn't wrong, it would be nice to be consistent.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Although now that I say that, none of these is particularly clear for stacks, at least (because forward or backward/reverse depends on the implementation).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
see the discussion in the corresponding issue. I was using backward_iter as the name from the discussion there, happy to change to reverse_iter.
Currently, the default iterator uses LIFO order for stacks and FIFO for queues, whereas forward_iter is always FIFO and backward_iter is always LIFO. I think it makes sense for the default iterator to use the ordering that makes sense for the particular data structure whereas the separate functions for forward_iter and backward_iter should be consistent across data structures. Let me know what you think about that
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@lindahua, who introduced those names, is coming from a C++ background, and in C++, the corresponding iterators are forward_iterator and backward_iterator.
Thinking more, I would actually prefer that, instead, we had a natural order iterator (the default), and a second, reverse_iter, which is just opposite of the default iteration. Reasons:
- It's easier to reason about--you don't have to understand how the underlying data structure is implemented, you only have to understand its default iteration order.
- At one point, a generic
reverseiterator (and correspondingReversetype) was implemented this way in Julia (it was later changed to return a concrete value). - It's one less function to create.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I modified things such that there are is a DequeIterator and a ReverseDequeIterator but the default iteration order is the DequeIterator for the deque object (i.e. if you just do
for i in dq
println(i)
end
it iterates in the order you expect it to). I still think it makes sense to define a forward_iter method which can optionally be used to get objects in a FIFO ordering and a reverse_iter method which can optionally be used to get objects in a LIFO ordering. Deque, Stack, and Queue have their default iteration order defined as FIFO, LIFO, and FIFO respectively and in most cases people should just use their default iteration order (perhaps to make this clearer we should have the iter function which returns the default iteration order for the particular type - generally I think most people would use the conventional iterator syntax for i in q as opposed to for i in forward_iter(q)), but if you particularly want things in LIFO order then you would use reverse_iter (and vice versa for FIFO order).
Let me know if you think that's simply overcomplicating things. Also, regardless of the direction we take, we should document this behavior clearly.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
actually I like the idea of leaving iter but having it return the default iterator for the type
|
Not going to have time to look at this closer right now, and the implementation is going to take some thought. I'll try to write more later. |
|
hm, good point around why |
src/deque.jl
Outdated
| i::Int | ||
| end | ||
|
|
||
| start_backward{T}(q::Deque{T}) = BackwardDequeIterator{T}(isempty(q), q.rear, q.head.back) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
q.head.back should be q.rear.back, right?
aa95e77 to
8609d2b
Compare
|
thanks @kmsquire, I built off your work there and made some changes in here. Will make some comments inline |
bcf9179 to
c968e9b
Compare
b91321d to
342a1c9
Compare
| cb = s.cblock | ||
| i::Int = s.i | ||
| x::T = cb.data[i] | ||
| start{T}(qi::DequeIterator{T}) = (qi.q.head, qi.q.head.front) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@kmsquire I also applied your cleanups to the existing iterator
|
Nice update! My preference, again, is to remove So, for example, the default The main idea is that I also think that @DanielArndt @lindahua any thoughts/opinion on this? |
|
@rawls238, in my email, I see a couple of other responses from you (where you argue the opposite point of view), but I don't see those comments here. Can you point them out, or repost them? |
|
Cc: @StefanKarpinski, who might have an opinion about reverse iteration. |
|
@kmsquire Are you looking for this discussion? #171 (comment) |
|
@kmsquire Re: iterators, I agree that the default iterator and It seems natural to me that the default iterator would iterate according to what you expect from the of the data structure, as you suggested. That being said, I am curious if there would be value in having a way to specifically specify that you would like a FIFO or FILO iterator which is, I think, what @rawls238 is suggesting. It definitely seems like a much less common use case. edit: I typed |
|
Yes that's what I'm suggesting, but I can see the appeal in just having the default iterator and reverse iterator since that simplifies things versus the approach I decided to take and makes it so that you don't have to think about the internals of stack and queue in order to decide what iterator to use (you just need to know the default iteration order for the particular data structure which should be documented). Unless anyone else thinks having explicit LIFO / FIFO iterators is a good idea, I'll change this to follow the default / reverse pattern. |
342a1c9 to
0051452
Compare
|
@kmsquire decided to just switch this to the interface you described. Also added a blurb in the docs about the iterators, let me know if you think this is good to go |
doc/source/stack_and_queue.rst
Outdated
| x = back(q) | ||
| x = dequeue!(q) | ||
|
|
||
| Both ``Stack`` and ``Queue`` implement the Iterator interface; iterating over ``Stack`` returns items in FILO order and iterating over ``Queue`` returns items in FIFO order. There is also a ``reverse_iter`` function implemented for both which returns items in the reverse order for each type (i.e. FIFO for ``Stack`` and FILO for ``Queue``). |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I've always seen FILO written as LIFO...
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That's my fault! I started mix matching a few things yesterday. A good sign that one needs more sleep.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
heh yea I also thought this was strange, but the docs already were using FILO so I figured I would follow them here. I'll switch everything in this file to LIFO
|
Other than those comments, LGTM. |
0051452 to
a97d15e
Compare
|
thanks for reviewing this @kmsquire, @DanielArndt |
use standard iterator for Stack + Queue Fixes #116
@kmsquire
This moves the iterator for stack and queue to conform to iterators such as those in https://github.com/JuliaLang/Iterators.jl
It effectively just calls down and utilizes the iterator for
Deque