"for each" loop?

8 messages Options
Embed this post
Permalink
Martin Piskernig

"for each" loop?

Reply Threaded More More options
Print post
Permalink
Hi!

I think it would be very helpful if you could add some kind of a "for
each" loop, that traverses collections element by element, to Eiffel. I
really miss it as a quick and powerful (syntactical) tool when often
switching from Java to Eiffel.

In Eiffel I usually have to write:

...
local
   elem:T
...
from list.start until list.off loop
   elem := list.item
   ... do something with elem ...
   list.forth
end

This could be much abbreviated to:

for list as elem loop
   ... do something with elem ...
end

(or whatever keyword you like instead of "for", that's not the point)

The foreach loop should be possible for every collection that inherits
from TRAVERSABLE, or rejected by the compiler otherwise.

I have read that, in the past, new variants of loops have been rejected
because of some principle that says that in Eiffel there should be
exactly ony way to "do it". This principle does not seem sound to me in
that it is broken in many ways by Standard Eiffel ("if"
vs. "inspect", "what" note vs. header comment, etc.).

Regards,
Martin
peter7723

Re: "for each" loop?

Reply Threaded More More options
Print post
Permalink
--- In [hidden email], Martin Piskernig <martin.piskernig@...> wrote:
>
> Hi!
>
> I think it would be very helpful if you could add some kind of a "for
> each" loop, that traverses collections element by element, to Eiffel.

The features do_all, do_if, there_exists and for_all are supplied in class TRAVERABLE[G] and in class ARRAY[G].

So, you can write
   list.do_all(agent item_procedure_feature)
which will execute item.item_procedure_feature for every item.

Peter Horan


rfo

RE: "for each" loop?

Reply Threaded More More options
Print post
Permalink
In reply to this post by Martin Piskernig
Hi Martin

You might (in the mean time :)) have a look at the iterators within the
containers.  They can be handy for simple loops over contents.  Have a
look at LINEAR's do_all, do_if, and for_all features.

     R

==================================================
Roger F. Osmond


> -------- Original Message --------
> Subject: [eiffel_software] "for each" loop?
> From: Martin Piskernig <[hidden email]>
> Date: Fri, September 18, 2009 7:08 pm
> To: [hidden email]
> Hi!
> I think it would be very helpful if you could add some kind of a "for
> each" loop, that traverses collections element by element, to Eiffel. I
> really miss it as a quick and powerful (syntactical) tool when often
> switching from Java to Eiffel.
> In Eiffel I usually have to write:
> ...
> local
>    elem:T
> ...
> from list.start until list.off loop
>    elem := list.item
>    ... do something with elem ...
>    list.forth
> end
> This could be much abbreviated to:
> for list as elem loop
>    ... do something with elem ...
> end
> (or whatever keyword you like instead of "for", that's not the point)
> The foreach loop should be possible for every collection that inherits
> from TRAVERSABLE, or rejected by the compiler otherwise.
> I have read that, in the past, new variants of loops have been rejected
> because of some principle that says that in Eiffel there should be
> exactly ony way to "do it". This principle does not seem sound to me in
> that it is broken in many ways by Standard Eiffel ("if"
> vs. "inspect", "what" note vs. header comment, etc.).
> Regards,
> Martin

Bertrand Meyer

RE: "for each" loop?

Reply Threaded More More options
Print post
Permalink
In reply to this post by Martin Piskernig
There is a proposal for an extension to the loop syntax which will provide
this mechanism. It should be available in experimental form (prior to
adoption by the Ecma committee) soon. As soon as I have a minute I will post
a blog entry about it.

 

--  BM

 

From: [hidden email]
[mailto:[hidden email]] On Behalf Of Martin Piskernig
Sent: 19 September, 2009 01:09
To: [hidden email]
Subject: [eiffel_software] "for each" loop?

 

 

Hi!

I think it would be very helpful if you could add some kind of a "for
each" loop, that traverses collections element by element, to Eiffel. I
really miss it as a quick and powerful (syntactical) tool when often
switching from Java to Eiffel.

In Eiffel I usually have to write:

...
local
elem:T
...
from list.start until list.off loop
elem := list.item
... do something with elem ...
list.forth
end

This could be much abbreviated to:

for list as elem loop
... do something with elem ...
end

(or whatever keyword you like instead of "for", that's not the point)

The foreach loop should be possible for every collection that inherits
from TRAVERSABLE, or rejected by the compiler otherwise.

I have read that, in the past, new variants of loops have been rejected
because of some principle that says that in Eiffel there should be
exactly ony way to "do it". This principle does not seem sound to me in
that it is broken in many ways by Standard Eiffel ("if"
vs. "inspect", "what" note vs. header comment, etc.).

Regards,
Martin





[Non-text portions of this message have been removed]

rfo

RE: "for each" loop?

Reply Threaded More More options
Print post
Permalink
In reply to this post by Martin Piskernig
Hello Bertrand!

Quite a while ago I asked for your impression regarding a proposal
I had tossed around with Manu regarding increment/decrement operators
and using them to add a for-loop like option to the Eiffel loop
constuct.
I'm pretty sure I never gave you the original text on that discussion.

Well, after some searching, inspired by the most recent query on the
yahoo group, I found the original, posted in March of 2007 to the
dev.eiffel.com site as "Auto-Increment_Proposal" (with 1,371 accesses
to date).  Don't let the title fool you, it's more about loops.

The original intent of the proposal was to add an increment operator.
What was different was the concept of treating integers (and characters)

as values in a predictable sequence, rather than simply as values in a
vaccuum.
This thinking leads to "forth" and "back" functions, where an
integer.forth would move the integer object forth along the number line
to the next value.
A character.forth would move the object's value forward on step in
its collating sequence.

Model wise, I guess integers would be BILINEAR and INFINITE, in that
they
could be traversed forth and back, but never finish.  They could be
further
qualified as having a median or origin of 0.  Characters would be
finite, bounded by their collating sequences.

This leads us to the loop enhancements, adding an increment clause to
the current loop construct.

If traversable lists, linear structures and integers shared common
ancestors
that provided the abstract notion of iteration (a la forth and back),
then it should be possible to add to the loop construct an expression
that drives the loop iteration - the one missing piece.  Here is an
example.

  from i := 1
  until i > 5
  by i.forth
  loop
      {loop body}
  end

The 'by' keyword introduces the iterator clause which includes the
iterator statement to be executed on each loop iteration.  In this case,

it's a simple procedure call to i.forth. It can as easily be any
statement,
even an agent.  I think the latter case opens up the possibility of
creating a more usable external iterator class by the way, but that's
a topic for another time.

The same constuct works for a list, as in:

  from list.start
  until list.after
  by list.forth
  loop
      {loop body}
  end

or a character, as in:

  from c := 'A'
  until c > 'Z'
  by c.forth
  loop
      {loop body}
  end

Because the iterator clause is optional, there is no issue of backward
compatibility.  All existing (and future) loops without an iterator
clause would be just fine.

An alternative would have the iterator clause at the bottom of the loop.


  from i := 1
  until i > 5
  loop
      {loop body}
  by i.forth
  end

While this more closely resembles the way a lot of code is written by
hand, to my thinking it has less value because it splits the loop
specification into 2 sections, possibly widely separated.  It also adds
confusion, in my mind.
I much prefer the spec being all together at the top.  It just reads
better as a spec, and I think it would encourage forethought - resulting

in more reliable loops.  Leaving the iterator to the end is just asking
for incomplete thinking.

One interesting wrinkle is the do-while/while-do issue.  Some loops will
want the iterator to execute at the top, and others will want it to
execute at the bottom.  One might conclude that the latter supports the
form I just said I hated, but it does not.  It is possible to have both
flavors, while keeping the loop specification clauses together.

  from i := 1
  until i > 5
  loop
  by i.forth
      {loop body}
  end

Having the iterator clause after the loop keyword specifies that the
iteration will occur after the body of the loop.  Having the original
form, with the iterator clause before the loop keyword specifies that
the iteration will occur before the body of the loop.
I can see how this might be confusing for some.

Another alternative might be to borrow from conditions, and use 'then'
to denote sequence, as in:

  from i := 1
  until i > 5
  loop then i.forth
      {loop body}
  end

  from i := 1
  until i > 5
  i.forth then loop
      {loop body}
  end

The first form being at-bottom and the second form being at-top,
Note well that the 'by' keyword is no longer needed in this form,
as the 'then' keyword should be sufficient.
This is my preferred form at the moment.

Another option might be to drop the keyword altogether. The presence
of a legitimate statement itself might be adequate. The construct then
would look like this.

  from i := 1
  until i > 5
  i.forth -- Or i++ if such an alias exists
  loop
      (loop body)
  end

I don't like this at all, but it does more closely resemble a for loop.
I think it fails in just about every other way.

How does all this impact loop-level assertions?  I think there is
potential
to have a very positive impact.  At present, loop assertions are a
mystery
to many.  I use them, but not all the time (shame on me).

Newbies simply freak out, especially when confronted with the rules for
loop variants.  By including the iterator statement in the loop spec, it

should be possible to generate loop variants automatically (and
correctly).

Loop invariants remain as before.

We could have another switch in the system configuration to enable
automatic loop variant assertions.  They would exist only for those
loops with a complete specification - i.e. with an iterator expression.

Those folks who use loops and indices the most I think would welcome
this feature and the forth/++ extension to integer.



     R

==================================================
Roger F. Osmond


> -------- Original Message --------
> Subject: RE: [eiffel_software] "for each" loop?
> From: Bertrand Meyer <[hidden email]>
> Date: Sat, September 19, 2009 10:05 am
> To: <[hidden email]>
> There is a proposal for an extension to the loop syntax which will provide
> this mechanism. It should be available in experimental form (prior to
> adoption by the Ecma committee) soon. As soon as I have a minute I will post
> a blog entry about it.
>  
> --  BM
>  
> From: [hidden email]
> [mailto:[hidden email]] On Behalf Of Martin Piskernig
> Sent: 19 September, 2009 01:09
> To: [hidden email]
> Subject: [eiffel_software] "for each" loop?
>  
>  
> Hi!
> I think it would be very helpful if you could add some kind of a "for
> each" loop, that traverses collections element by element, to Eiffel. I
> really miss it as a quick and powerful (syntactical) tool when often
> switching from Java to Eiffel.
> In Eiffel I usually have to write:
> ...
> local
> elem:T
> ...
> from list.start until list.off loop
> elem := list.item
> ... do something with elem ...
> list.forth
> end
> This could be much abbreviated to:
> for list as elem loop
> ... do something with elem ...
> end
> (or whatever keyword you like instead of "for", that's not the point)
> The foreach loop should be possible for every collection that inherits
> from TRAVERSABLE, or rejected by the compiler otherwise.
> I have read that, in the past, new variants of loops have been rejected
> because of some principle that says that in Eiffel there should be
> exactly ony way to "do it". This principle does not seem sound to me in
> that it is broken in many ways by Standard Eiffel ("if"
> vs. "inspect", "what" note vs. header comment, etc.).
> Regards,
> Martin
> [Non-text portions of this message have been removed]

Bertrand Meyer

RE: "for each" loop?

Reply Threaded More More options
Print post
Permalink
Dear Roger:

 

I see the usefulness of a “by” clause but am uneasy about its relationship to the “loop” clause. It is not always clear what is the body and what is the advance.

 

For example in Euclid’s algorithm

 

                from

                                x := a ; y := b

                invariant

                                gcd (x, y) = gcd (a, b)

                until

                                x = y

                loop

                                if x > y then

                                                x := x – y

                                else

                                                y := y –x

                                end

                variant

                                max (x, y)            -- Or: x + y

                end

 

the conditional instruction is both body and advance.

 

Framing the matter in theory, any loop is of the following form, where S is a subset of the data:

 

                from

                                “Establish INV on trivial subset S”

                invariant

                                INV

                until

                                “S is the entire data set”

                loop

                                “Extend S so that INV holds on resulting S” --  [LB]

                variant

                                “|Data - S|” -- i.e. size of subset of data not yet covered

                end

 

where INV applied to the entire data is the desired postcondition.

 

It is fairly common that the loop body [LB], “Extend S so that INV holds on resulting S”, naturally splits itself into a sequence of two actions:

 

                “Add items to S”                                                               -- [1] (This may break INV)

                “Fix state to ensure that INV holds on S”               -- [2]

 

In that case the distinction between body and advance is clear: [1] is the advance (“by” clause) and [2} is the body (“loop”). A simple example is the obvious loop to compute the sum of elements of an array or list of integers.

 

But not all cases expand [LB] in such a straightforward ways. For examples that do not, I find the distinction between “loop” and “by” more confusing than helpful.

 

You might like the proposed generalized iteration -- I will post about it.


Thanks,

 

-- BM

 

 

From: [hidden email] [mailto:[hidden email]] On Behalf Of [hidden email]
Sent: 19 September, 2009 17:29
To: [hidden email]
Subject: RE: [eiffel_software] "for each" loop?

 

 

Hello Bertrand!

Quite a while ago I asked for your impression regarding a proposal
I had tossed around with Manu regarding increment/decrement operators
and using them to add a for-loop like option to the Eiffel loop
constuct.
I'm pretty sure I never gave you the original text on that discussion.

Well, after some searching, inspired by the most recent query on the
yahoo group, I found the original, posted in March of 2007 to the
dev.eiffel.com site as "Auto-Increment_Proposal" (with 1,371 accesses
to date). Don't let the title fool you, it's more about loops.

The original intent of the proposal was to add an increment operator.
What was different was the concept of treating integers (and characters)

as values in a predictable sequence, rather than simply as values in a
vaccuum.
This thinking leads to "forth" and "back" functions, where an
integer.forth would move the integer object forth along the number line
to the next value.
A character.forth would move the object's value forward on step in
its collating sequence.

Model wise, I guess integers would be BILINEAR and INFINITE, in that
they
could be traversed forth and back, but never finish. They could be
further
qualified as having a median or origin of 0. Characters would be
finite, bounded by their collating sequences.

This leads us to the loop enhancements, adding an increment clause to
the current loop construct.

If traversable lists, linear structures and integers shared common
ancestors
that provided the abstract notion of iteration (a la forth and back),
then it should be possible to add to the loop construct an expression
that drives the loop iteration - the one missing piece. Here is an
example.

from i := 1
until i > 5
by i.forth
loop
{loop body}
end

The 'by' keyword introduces the iterator clause which includes the
iterator statement to be executed on each loop iteration. In this case,

it's a simple procedure call to i.forth. It can as easily be any
statement,
even an agent. I think the latter case opens up the possibility of
creating a more usable external iterator class by the way, but that's
a topic for another time.

The same constuct works for a list, as in:

from list.start
until list.after
by list.forth
loop
{loop body}
end

or a character, as in:

from c := 'A'
until c > 'Z'
by c.forth
loop
{loop body}
end

Because the iterator clause is optional, there is no issue of backward
compatibility. All existing (and future) loops without an iterator
clause would be just fine.

An alternative would have the iterator clause at the bottom of the loop.

from i := 1
until i > 5
loop
{loop body}
by i.forth
end

While this more closely resembles the way a lot of code is written by
hand, to my thinking it has less value because it splits the loop
specification into 2 sections, possibly widely separated. It also adds
confusion, in my mind.
I much prefer the spec being all together at the top. It just reads
better as a spec, and I think it would encourage forethought - resulting

in more reliable loops. Leaving the iterator to the end is just asking
for incomplete thinking.

One interesting wrinkle is the do-while/while-do issue. Some loops will
want the iterator to execute at the top, and others will want it to
execute at the bottom. One might conclude that the latter supports the
form I just said I hated, but it does not. It is possible to have both
flavors, while keeping the loop specification clauses together.

from i := 1
until i > 5
loop
by i.forth
{loop body}
end

Having the iterator clause after the loop keyword specifies that the
iteration will occur after the body of the loop. Having the original
form, with the iterator clause before the loop keyword specifies that
the iteration will occur before the body of the loop.
I can see how this might be confusing for some.

Another alternative might be to borrow from conditions, and use 'then'
to denote sequence, as in:

from i := 1
until i > 5
loop then i.forth
{loop body}
end

from i := 1
until i > 5
i.forth then loop
{loop body}
end

The first form being at-bottom and the second form being at-top,
Note well that the 'by' keyword is no longer needed in this form,
as the 'then' keyword should be sufficient.
This is my preferred form at the moment.

Another option might be to drop the keyword altogether. The presence
of a legitimate statement itself might be adequate. The construct then
would look like this.

from i := 1
until i > 5
i.forth -- Or i++ if such an alias exists
loop
(loop body)
end

I don't like this at all, but it does more closely resemble a for loop.
I think it fails in just about every other way.

How does all this impact loop-level assertions? I think there is
potential
to have a very positive impact. At present, loop assertions are a
mystery
to many. I use them, but not all the time (shame on me).

Newbies simply freak out, especially when confronted with the rules for
loop variants. By including the iterator statement in the loop spec, it

should be possible to generate loop variants automatically (and
correctly).

Loop invariants remain as before.

We could have another switch in the system configuration to enable
automatic loop variant assertions. They would exist only for those
loops with a complete specification - i.e. with an iterator expression.

Those folks who use loops and indices the most I think would welcome
this feature and the forth/++ extension to integer.

R

==================================================
Roger F. Osmond

> -------- Original Message --------
> Subject: RE: [eiffel_software] "for each" loop?
> From: Bertrand Meyer <[hidden email] <mailto:Bertrand.Meyer%40inf.ethz.ch> >
> Date: Sat, September 19, 2009 10:05 am
> To: <[hidden email] <mailto:eiffel_software%40yahoogroups.com> >
> There is a proposal for an extension to the loop syntax which will provide
> this mechanism. It should be available in experimental form (prior to
> adoption by the Ecma committee) soon. As soon as I have a minute I will post
> a blog entry about it.
>
> -- BM
>
> From: [hidden email] <mailto:eiffel_software%40yahoogroups.com>
> [mailto:[hidden email] <mailto:eiffel_software%40yahoogroups.com> ] On Behalf Of Martin Piskernig
> Sent: 19 September, 2009 01:09
> To: [hidden email] <mailto:eiffel_software%40yahoogroups.com>
> Subject: [eiffel_software] "for each" loop?
>
>
> Hi!
> I think it would be very helpful if you could add some kind of a "for
> each" loop, that traverses collections element by element, to Eiffel. I
> really miss it as a quick and powerful (syntactical) tool when often
> switching from Java to Eiffel.
> In Eiffel I usually have to write:
> ...
> local
> elem:T
> ...
> from list.start until list.off loop
> elem := list.item
> ... do something with elem ...
> list.forth
> end
> This could be much abbreviated to:
> for list as elem loop
> ... do something with elem ...
> end
> (or whatever keyword you like instead of "for", that's not the point)
> The foreach loop should be possible for every collection that inherits
> from TRAVERSABLE, or rejected by the compiler otherwise.
> I have read that, in the past, new variants of loops have been rejected
> because of some principle that says that in Eiffel there should be
> exactly ony way to "do it". This principle does not seem sound to me in
> that it is broken in many ways by Standard Eiffel ("if"
> vs. "inspect", "what" note vs. header comment, etc.).
> Regards,
> Martin
> [Non-text portions of this message have been removed]





[Non-text portions of this message have been removed]

Bertrand Meyer

Intended formatting RE: "for each" loop?

Reply Threaded More More options
Print post
Permalink
It seems the formatting of my message was lost. It should be more readable at

 

                http://se.ethz.ch/~meyer/down/foreach.txt

 

 

 

From: [hidden email] [mailto:[hidden email]] On Behalf Of Bertrand Meyer
Sent: 19 September, 2009 19:22
To: [hidden email]
Subject: RE: [eiffel_software] "for each" loop?

 

 

Dear Roger:

I see the usefulness of a “by” clause but am uneasy about its relationship to the “loop” clause. It is not always clear what is the body and what is the advance.

For example in Euclid’s algorithm

f

 



[Non-text portions of this message have been removed]

Martin Piskernig

Re: "for each" loop?

Reply Threaded More More options
Print post
Permalink
In reply to this post by Bertrand Meyer
On Samstag, 19. September 2009, Bertrand Meyer wrote:
> There is a proposal for an extension to the loop syntax which will provide
> this mechanism. It should be available in experimental form (prior to
> adoption by the Ecma committee) soon. As soon as I have a minute I will
> post a blog entry about it.

Bertrand, thank you very much for your answer! I eagerly await your blog
post :-)

Kind regards,
Martin


------------------------------------

Yahoo! Groups Links

<*> To visit your group on the web, go to:
    http://groups.yahoo.com/group/eiffel_software/

<*> Your email settings:
    Individual Email | Traditional

<*> To change settings online go to:
    http://groups.yahoo.com/group/eiffel_software/join
    (Yahoo! ID required)

<*> To change settings via email:
    mailto:[hidden email]
    mailto:[hidden email]

<*> To unsubscribe from this group, send an email to:
    [hidden email]

<*> Your use of Yahoo! Groups is subject to:
    http://docs.yahoo.com/info/terms/