couple of really noob questions (ranges, toString)

Jonathan M Davis jmdavisProg at gmx.com
Mon Nov 1 20:40:30 PDT 2010


On Monday 01 November 2010 19:21:27 spir wrote:
> On Mon, 1 Nov 2010 18:47:38 -0700
> 
> Jonathan M Davis <jmdavisProg at gmx.com> wrote:
> > The best place to start learning about ranges is probably here:
> > http://www.informit.com/articles/article.aspx?p=1407357
> > 
> > front, popFront(), and empty make perfect sense as they are and work
> > quite well. hasNext() and next() have the serious drawback of mixing
> > iterating through the range and getting an element in it. It's one of
> > the serious flaws in Java's iterators. It's far better to have getting
> > the current or front element be separate from moving or  popping the
> > next one.
> 
> Thank for the pointer.
> Note That I know exactly nothing of Java. In fact, I used this scheme and
> those names spontaneously to implement traversal of custom structs in
> Oberon (that has no such notion). There's a point I don't understand in
> your argument: "...the serious drawback of mixing iterating through the
> range and getting an element in it". Isn't this precisely what popFront()
> does, stepping and returning an element? Or is "pop" in "popFront"
> misleading? (I've followed your pointer, but the site is so designed that
> the article is spread over 15 pages!) To move forward without popping,
> you'd need a kind of step() method that just follows the next pointer;
> really complementary to front(). Or is there something I misunderstand?
> But since typical use is iteration, does it make sense to separate
> stepping and reading? I now realise that my previous comment on the method
> trio vs my point of view is wrong; the functionality is the same, done the
> same way, only naming reveals a different pov: next() is popFront() seen
> differently, hasNext() is !empty().

In C++, iterators are effectively pointers. ++ increments, -- decrements, and * 
dereferences the element that it currently points to. The same goes for C#, 
except that they didn't overload * to get the current element but rather used a 
property function (Current IIRC, but I haven't used C# in a while). In both 
cases, accessing the current element does not move the iterator. Moving the 
iterator is completely separate from accessing what it points to.

In Java, on the other hand, they have hasNext(), hasPrev(), next(), and 
previous(), and the iterator doesn't point _at_ a particular element but rather 
_between_ them. So, hasNext() and hasPrevious() return a bool telling you 
whether there is a next or previous element respectively. next() returns the 
next element and moves the iterator whereas previous() returns the previous 
iterator and moves the iterator backwards. It means that you have to save the 
element every time that you access the next one rather than being able to use 
the iterator to get it again. It also makes it essentially impossible (or 
extremely ugly) to try and designate a range of any kind with iterators, since 
they don't actually point _at_ elements at using iterators alters them. Of 
course, Java didn't end up using iterators in a fashion that algorithms could be 
used for them (like C++ did), but it would be a pain even if you tried due to 
the lack of separation between moving an iterator and accessing what it refers 
to.

D uses ranges, which are at their most basic a pair of iterators but which are 
far more flexible than that, since you don't have to actually use iterators for 
their implementation. Things like infinite ranges become possible, which aren't 
really doable in the same way with iterators. They also completely avoid the 
issues related to passing iterators in the wrong order or which point to 
different containers.

There are various types of ranges, each with a set of functions that they must 
have, but the most basic is an InputIterator which has front, popFront(), and 
empty. front gives the first element in the range without altering the range. 
popFront() pops the first element from the range, making the next elment (if any) 
the first element in the range. popFront() is void and does not return what it 
pops. empty indicates whether there are any more elements left in the range. 
Using front when a range is empty will generally result in an exception being 
thrown, because there is no first element in the range.

The term "pop" does _not_ mean that an element is returned but that it is 
removed from the range. This is true for pretty much anything that uses a pop 
function in any language - stacks, lists, etc. It _is_ true that many 
implementations choose to have pop return the element which is popped, but 
that's an implementation detail. The term pop merely indicates that an element 
is removed from an end of a range or container.

- Jonathan M Davis


More information about the Digitalmars-d-learn mailing list