Allison Randal wrote:

> You know, I almost made a very similar reply. But I read through
> Damian's message a second time and changed my mind. C<BETWEEN> makes
> sense as a C<NEXT> minus C<LAST>. As a C<PRE> minus C<FIRST> it's less
> appealing. At the very least it begs a different name than "BETWEEN" (a
> name that implies it executes "between" each loop, not at the beginning
> of some).
> 
> Hmmm... would C<LAST> not have the same problem as C<BETWEEN>? It also
> "can't decide whether to execute until it knows whether the loop is
> going to iterate again".

I've been watching this "Loop controls" thread with much interest.  It
is clear that there is some convenience in the concept of specialized
blocks that execute FIRST or LAST or NEXT and BETWEEN has a large
appeal, considering the large number of loops where something must be
done every time except the first or every time except the last, except
that I have never done the statistics to figure out whether every time
except the last or every time except the first is more frequent, neither
have I figured out whether BETWEEN is more frequently needed at the
beginning or end of the loop body, and these latter two issues seem to
be what everyone is going around and around about, without stating them.

I think much of the discussion has resulted because there are many more
conceptual meanings that could be useful, than there are suggested
keywords to fulfil the meanings.  I'll try to list the many conceptual
meanings possible as I continue.

As specialized blocks, the order is implicit, which means that separate
specialized blocks would be needed for the four cases of BETWEEN which
are:

BETWEEN A) execute before the loop body every time except the first
BETWEEN B) execute before the loop body every time except the last
BETWEEN C) execute after the loop body every time except the first
BETWEEN D) execute after the loop body every time except the last

There has also been discussion about the "best" order of placement of
the specialized loop blocks within the block, vs. the implicit execution
order, and how that could be confusing sometimes.

One thing I've noticed omitted from the discussion is that there are
also cases such where the FIRST and BETWEEN might want to share code, or
even the FIRST block might want to know if it is the last iteration.

There has been the comment made that detection of the last iteration is
hard (except, of course, for loop blocks with finite sequences) during
the last iteration, that it is only after the last iteration that it is
known that that iteration was, indeed, the last.

It seems extremely trivial, however, to detect whether a particular
iteration is the first.

Now it could be said that LAST isn't needed, that you could just code
that logic after the loop, but it seems to be true that LAST is only
executed if the loop ever performs at least one iteration (and an
explicit last statement is executed) or the iteration condition becomes
false.  This is a useful concept that (1) cannot be easily detected by
user logic but can always be easily detected by the language loop
control logic.  The LAST block would certainly be a way to detect that,
but the two cases differ: an explicit last statement could cause
execution of the LAST block in the scope and with the variable values of
the last iteration, but when the iteration condition becomes false, the
scope and variable values are gone (unless heroically preserved, which
probably could happen, but may have other nasty side effects that would
be hard to understand).  Also, the discussion of "else" conditions on
loops seems very similar to LAST, so maybe we need five different LAST
blocks:

LAST A) executes when an explicit last statement occurs, in the scope of
the last iteration
LAST B) executes when the iteration condition becomes false, if at least
one iteration has occurred
LAST C) executes when the iteration condition becomes false, if there
have been no iterations
LAST D) legal only with loop loop: executes during the last iteration of
a loop, before the loop body
LAST E) legal only with loop loop: executes during the last iteration of
a loop, after the loop body

NEXT seems pretty simple: it executes after the loop body of an
iteration, just before the iteration condition is reevaluated.

Even FIRST could have two useful meanings:

FIRST A) executes during the first iteration of a loop, before the loop
body
FIRST B) executes during the first iteration of a loop, after the loop
body


So it seems pretty clear that no amount of discussion will ever allow a
few keywords to fulfil all of the possible variant implementations that
might be possible and even useful, in various circumstances.

I see several possible courses of action, there are perhaps more.

1) Choose the "most useful" meaning out of the above collections of
possibilities, and disregard the others, forcing people who want to code
them to "do it the old way" with discrete logic.

2) Invent new keywords for each possibility, proliferating keywords, and
likely resulting in similar keywords having slightly different meanings,
which could be easily confused, especially by newcomers.

3) Take a different approach to some of the issues.

I'll outline a different approach that addresses at least a large number
of the above possibilities, starting from the simplest.

NEXT:

The next statement is simple, but often there is logic that wants to be
executed when it is known that the loop body is otherwise finished.  A
NEXT block could contain that, and it is pretty clear that a NEXT block
would be executed after the loop body for an iteration.


FIRST:

Many times I've encountered situations where the special things that
need to be executed during the first iteration of the loop cannot be
gathered together to be executed first, nor can they be gathered
together to be executed last.  These seem like the only possibilities
for a specialized FIRST block to be executed, and they don't cover the
territory.  Really, the concept of the FIRST iteration needs to be
distributed and available throughout the loop body, and even available
during NEXT blocks and LAST blocks.  Instead of a FIRST block, I would
recommend that all loop scopes contain a value or property that can be
easily tested to determine if this code is executing as part of the
first iteration or not.  I hesitate to suggest syntax, but at least for
loops that are part of a named block named NAME, perhaps  NAME.first 
would work, or whatever works.  I'll use this syntax for this
discussion, but I'm not really suggesting it.

Note that LAST D and LAST E are similar concepts, need to be similarly
distributed, and could be resolved with a similar solution:  NAME.last
or whatever, but as a testable flag.

For those cases where the logic can be gathered together, the following
implementations could be used:

FIRST A:  PRE { if NAME.first { ... }}
FIRST B:  NEXT { if NAME.first { ... }}  or maybe  POST { if NAME.first
{ ... }}


BETWEEN:

Here are some implementations for variations of BETWEEN:

BETWEEN A: PRE { unless NAME.first { ... }}
BETWEEN B: PRE { unless NAME.last { ... }}
BETWEEN C: NEXT { unless NAME.first { ... }}
BETWEEN D: NEXT { unless NAME.last { ... }}

Perhaps that is good enough, and no special BETWEEN block is needed.


LAST:

I'd suggest handling LAST D and LAST E as described in the section on
FIRST, with testable flags.  However, here are alternate implementations
for them in the cases where the logic can be gathered together:

LAST D: PRE { if NAME.last { ... }}
LAST E: NEXT { if NAME.last { ... }}  or maybe  POST { if NAME.last {
.... }}

LAST A seems like a good candidate for a special block, to be executed
in the scope and with the variables of the last iteration.

LAST B and LAST C don't seem to be easily able to have available to them
the variables and scope of the final iteration, since it is complete
before they are known to be callable.  LAST B could invoke a specialized
block named FINISH and LAST C could invoke a specialized block named
INSTEAD.  Or, an additional state flag such as NAME.last could be set,
to indicate that a LAST block was entered by an explicit last statement
or not, and the same LAST block could be used for all these cases. 
Discrimination between LAST B and LAST C in that case could be done by
checking the iteration counter, which could be NAME.count, and would be
useful in lots of circumstances anyway.

-- 
Glenn
=====
Remember, 84.3% of all statistics are made up on the spot.

Reply via email to