Board index » delphi » Iterator...being anal

Iterator...being anal


2003-08-16 07:23:01 AM
delphi42
I'm being overly {*word*7}about this one...but I have a general question of
preference.
If we have an iterator, which would be prefered and why:
IIterator = interface
procedure Next;
function IsMore: boolean;
function Current: IInterface;
end;
where:
localIterator := CSomeFactory.MakeNew;
while localIterator.IsMore do
begin
...
localIterator.Next;
end;
or
IIterator = interface
function Each: boolean;
function Current: IInterface;
end;
where:
localIterator := CSomeFactory.MakeNew;
while localIterator.Each do
begin
...
end;
Thoughts...comments...thesis?
John
 
 

Re:Iterator...being anal

"John Elrick" <XXXX@XXXXX.COM>writes
Quote
I'm being overly {*word*7}about this one...but I have a general question of
preference.
Quote
IIterator = interface
function Each: boolean;
function Current: IInterface;
end;

where:
localIterator := CSomeFactory.MakeNew;
while localIterator.Each do
begin
...
end;
Hands down ;-)
The whole point IMO is to save the extra operation. The other approach
doesn't really add any value over a for-loop IMO.
This one does.
 

Re:Iterator...being anal

"Alessandro Federici" <XXXX@XXXXX.COM>writes
Quote
The other approach doesn't really add any value over a for-loop IMO.
Meaning in the for-loop you need a var declaration and the loop line while
with this one only one thing (the while).
 

Re:Iterator...being anal

Bob Dawson writes:
|| while localIterator.Next do
|| begin
|| ...
|| end;
|
| and implies that the iterator begins with Current positioned at -1 (before
| the first item). Don't know what others do here, but I always open
| iterators positioned on the first item (if items exist).
I tend to use this style of Iterator, but with an additional operation:
IIterator = interface
function Next: Boolean;
function CurrentItem: IInterface;
procedure Reset;
end;
Setting the position to before the first item, allows the very simple syntax
of:
while Iter.Next do
CurrentItem.SomeOperation;
or for looking for an item:
while iter.Next and (Result <>nil) do
if Iter.CurrentItem.SomeProp = SearchValue then
Result := Iter.CurrentItem;
The Reset method is very useful for using the same iterator more than once
:-)
Joanna
 

Re:Iterator...being anal

"Joanna Carter" wrote
Quote

while iter.Next and (Result <>nil) do
if Iter.CurrentItem.SomeProp = SearchValue then
Result := Iter.CurrentItem;
This results in the (to me) non-intuitive side effect that the iterator will
be left positioned one item past the Result. Not crucial, I suppose, but I'd
normally expect an iterator that just found something to be left positioned
on what it found.
Two questions--
Circular buffer? IOW would calling Next again after a false return give you
the first item again? Needs an implementation something like
function TIeratorImp.Next; boolean;
begin
inc(CurrPos);
if CurrPos < Items.Count then
Result := true
else
begin
Result := false;
Reset;
end;
end;
That would allow the following code
while iter.Next do
SomeProcss(CurrentItem);
while iter.Next do
SomeOtherProcss(CurrentItem);
Quote
The Reset method is very useful for using the same iterator more than once
If you're implementing a Reset (which the way I am doing it is called First),
do you a also ever match Next with Prior, allowing reverse iteration?
iter.Reset; //(assumes circular buffer as above)
while iter.Prior do
SomeProcss(CurrentItem);
bobD
 

Re:Iterator...being anal

John Elrick writes:
Quote
while localIterator.IsMore do
begin
...
localIterator.Next;
end;

or

while localIterator.Each do
begin
...
end;
I think "Each" only reads right as part of a For Each language feature.
Without For Each, I think
while localIterator.IsMore do
(or while not localIterator.Eof do)
is better.
--
Wayne Niddery - Logic Fundamentals, Inc. (www.logicfundamentals.com)
RADBooks: www.logicfundamentals.com/RADBooks.html
"It is error alone which needs the support of government. Truth can
stand by itself." - Thomas Jefferson
 

Re:Iterator...being anal

"Alessandro Federici" wrote
Quote

Right but since they're both clear, less code wins IMO <G>
I think Next is pretty transparently an iterator-advance method--I like it
for the very reason that John dislikes it--it's a familiar term/idiom from
datasets. However, I'd tend to expect any Is<Whatever>property to be a
boolean condition test--not a command at all--this looks like a read-only
property with a side-effect to me.
Like Jim (apparently), I see the single line of code saved as a questionable
tradeoff for not capitalizing on an already transparent method name, and
programming by side-effect.
Depends on what you're used to I suppose.
bobD
 

Re:Iterator...being anal

"Wayne Niddery [TeamB]" <XXXX@XXXXX.COM>writes
Quote
I think "Each" only reads right as part of a For Each language feature.
Without For Each, I think
while localIterator.IsMore do
(or while not localIterator.Eof do)
is better.
Good point! I subscribe to this.
 

Re:Iterator...being anal

"Bob Dawson" <XXXX@XXXXX.COM>writes
Quote
But if consistency with the rest of the Delphi language is important (and
it
is), isn't Next the obvious iterator-advance choice?
If you only use Delphi yes, if you don't it might be less important or even
irrelevant if you considered your own naming standards better (I am not
saying I do, it is in general) ;-) Regardless, "Next" would definitely be
good too for me and yes, it is the best and more natural so far. Actually, I
made a class that uses exactly that for DA. I just forgot! ;-)
 

Re:Iterator...being anal

"Bob Dawson" <XXXX@XXXXX.COM>writes
Quote
Depends on what you're used to I suppose.
See my other reply.
 

Re:Iterator...being anal

"Jim Cooper" <XXXX@XXXXX.COM>writes
Quote

>The whole point IMO is to save the extra operation.

I'd say that the whole point is to be clear what's happening :-) An
extra line more or less here and there makes no odds - clarity is more
important. If fewer lines equalled increased readability we'd all be C
or Forth programmers or something :-)

I don't see any particular advantage in either choice over the GoF
choices of First, Next, IsDone and Current. You could add Prior, but
IsMore is an attempt to avoid the inevitable (and unnecessary) negation:
while not IsDone do
...
Perhaps IsNotDone
John
 

Re:Iterator...being anal

"Wayne Niddery [TeamB]" <XXXX@XXXXX.COM>writes
Quote
John Elrick writes:
>while localIterator.IsMore do
>begin
>...
>localIterator.Next;
>end;
>
>or
>
>while localIterator.Each do
>begin
>...
>end;

I think "Each" only reads right as part of a For Each language feature.
Without For Each, I think
Yea...the thought occurred to me while reviewing one of my Ruby manuals. I
agree that
while iterator.Each doesn't quite work as well as a true Each support
mechanism.
John
 

Re:Iterator...being anal

"Bob Dawson" <XXXX@XXXXX.COM>writes
Quote
"Alessandro Federici" wrote
>
>Right but since they're both clear, less code wins IMO <G>

I think Next is pretty transparently an iterator-advance method--I like it
for the very reason that John dislikes it--it's a familiar term/idiom from
datasets. However, I'd tend to expect any Is<Whatever>property to be
a
Except that Next in datasets doesn't behave the same way:
Table1.Open;
while Table1.Next do
First, it doesn't even compile, since Next is a procedure
Second, if it did compile, you would never process the first record.
FWIW
John
 

Re:Iterator...being anal

"John Elrick" wrote
Quote
"Bob Dawson" <XXXX@XXXXX.COM>writes
>I think Next is pretty transparently an iterator-advance method

First, it doesn't even compile, since Next is a procedure

Second, if it did compile, you would never process the first record.
Both true, but I don't see that they change the main point above. 'Next'
looks like it is doing something, 'IsMore' looks like a condition check that
I should be able to call repeatedly without side effects.
Synopsis: usage seems to be divided here between the two approaches, with
one side prefering to combine the iterator advance with position validation
as way to save a line of code
while iter.CanAdvance do
Process(iter.CurrItem)
while the other side prefers the clarity of making iteration movement
distinct from position validation
while iter.HasItem do
begin
Process(iter.CurrItem)
iter.Next;
end;
The style chosen must be compatible with initial/reset iterator positioning
//legal?
if ACollection.HasItems then
begin
iter := ACollection.ProvideIterator;
Process(iter.CurrentItem);
We can probably all agree that consistency across the problem
domain/framework is the highest goal: one should pick a style, document it
as necessary, and make all iterators conform.
bobD
 

Re:Iterator...being anal

Quote
IsMore is an attempt to avoid the inevitable (and unnecessary) negation:
So I gathered. It doesn't really improve readability a huge amount, but
if you like it...
Quote
Perhaps IsNotDone
I think that negatives in names are best avoided, as that way you can
get double negatives. If the names are always positives then they are
never necessary.
Cheers,
Jim Cooper
____________________________________________
Jim Cooper XXXX@XXXXX.COM
Tabdee Ltd www.tabdee.ltd.uk
TurboSync - Connecting Delphi with your Palm
____________________________________________