[comp.lang.ada] On quitting an Iterator Prematurely

sommar@enea.se (Erland Sommarskog) (04/08/90)

Norman H. Cohen (NCOHEN@IBM.COM) writes:
>Andre' Alguero asks about how to write a procedure to iterate over
>a set of discrete elements, specifying the actions to be performed
>at each iteration at the point at which the procedure is invoked.
>...
>One Ada solution is to nest a generic procedure inside a generic
>package.  The generic package is parameterized by the element type
>of the set.

This seems like the straight-forward and natural solution to do it.
In fact I suspected that I had misunderstood the original question,
since this design is not difficult to come up with.
  However, consider Mr. Cohen's proposal:

>   generic
>      type Element_Type is (<>);  -- some discrete type
>   package Set_Package is
>      type Set_Type is private;
>      -- Operations like union, intersection declared here...
>      generic
>         with procedure Process_One_Element (Element: in Element_Type);
>      procedure Process_Each_Element (Set: in Set_Type);

Some years ago I wrote a binary tree package with a similar concept.
When I was to use the package I discovered one thing I had missed.
There was no way to interrupt the iteration. One way is of course
to rewrite the package so that Process_one_element should take a
second parameter
   Continue : OUT boolean;
The problem with this is that if the user in 90% of the time wants to
iterate through the entire set, this second parameter just clutters
up his code, and he may even forget to initiate it with interesting
results, unless the compiler catches the error.
  So I went for the other solution and simply and the wrote invoking
procedure as:

   DECLARE
      done : EXCEPTION;
      PROCEDURE Test_One_Element (E : IN My_Element_Subtype) is
      BEGIN
         -- some stuff
         IF Found THEN
            RAISE Done;
         END IF;
      END Test_One_Element;

      PROCEDURE Find_First_Element IS NEW
         My_Set_Package.Process_Each_Element
            (Process_One_Element => Test_One_Element);
   BEGIN
      Find_First_Element (S);
   EXCEPTION
      WHEN Done => NULL;
   END;

Now, I wouldn't say that this is the use of exception as intended,
but rather a confirmation those who claim that says that exception is
a structured GOTO. Yet, if this is the rare case, this solution seem
to be preferable to a second, rarely-used continue parameter.

What is the general opinion on this? Any better ideas?
-- 
Erland Sommarskog - ENEA Data, Stockholm - sommar@enea.se

louboutn@ccvax.ucd.ie (Sylvain Louboutin, University College Dublin, Ireland) (04/11/90)

In article <1151@enea.se>, sommar@enea.se (Erland Sommarskog) writes:
> Norman H. Cohen (NCOHEN@IBM.COM) writes:
>>Andre' Alguero asks about how to write a procedure to iterate over
>>a set of discrete elements, specifying the actions to be performed
>>at each iteration at the point at which the procedure is invoked.
[...]
> Some years ago I wrote a binary tree package with a similar concept.
> When I was to use the package I discovered one thing I had missed.
> There was no way to interrupt the iteration. One way is of course
> to rewrite the package so that Process_one_element should take a
> second parameter
>    Continue : OUT boolean;
> The problem with this is that if the user in 90% of the time wants to
> iterate through the entire set, this second parameter just clutters
> up his code, and he may even forget to initiate it with interesting
> results, unless the compiler catches the error.

[Erland then proposes to use an exception to interrupt the iteration]

Why don't you write the procedure like this: (note that the 'continue' 
paramter mode is IN OUT instead o OUT)

      generic
         with procedure Process_One_Element (Element: in Element_Type;
                                             Continue : IN OUT boolean);
      procedure Process_Each_Element (Set: in Set_Type);


      procedure Process_Each_Element (Set: in Set_Type) is
        Continue: boolean := TRUE;
        -- other declaration...
      begin
        -- some statements
        loop 
           -- some statements
           Process_One_Element (Current_Element, Continue);
           exit when not Continue;
           -- some statements
        end loop;
        -- some statements...
      end Process_Each_Element;

The user (i.e. the programmer of the procedure 'Process_One_Element')
doesn't need to bother about the parameter continue (except that s/he
has to include it in the header of the procedure, but there is no need
to set a value to it in the procedure Process_Each_Element) if s/he
wants to iterate through all the set... 
-- 
-- Sylvain R.Y. Louboutin                         fax: (+353-1) 69-72-62
-- Dept of Computer Science, University College, Dublin 4, -- Ireland --
-- LOUBOUTN@CCVAX.UCD.IE, S_LOUBOUTIN@CS.UCD.IE, SLOUBH91@IRLEARN.BITNET

tdhammer@wsuiar.uucp (04/11/90)

In article <1151@enea.se>, sommar@enea.se (Erland Sommarskog) writes:

[stuff from Cohen deleted]

> 
> Some years ago I wrote a binary tree package with a similar concept.
> When I was to use the package I discovered one thing I had missed.
> There was no way to interrupt the iteration. One way is of course
> to rewrite the package so that Process_one_element should take a
> second parameter
>    Continue : OUT boolean;
> The problem with this is that if the user in 90% of the time wants to
> iterate through the entire set, this second parameter just clutters
> up his code, and he may even forget to initiate it with interesting
> results, unless the compiler catches the error.

[more stuff deleted - code example]

> Now, I wouldn't say that this is the use of exception as intended,
> but rather a confirmation those who claim that says that exception is
> a structured GOTO. Yet, if this is the rare case, this solution seem
> to be preferable to a second, rarely-used continue parameter.
> 
> What is the general opinion on this? Any better ideas?
> -- 
> Erland Sommarskog - ENEA Data, Stockholm - sommar@enea.se

My first reaction was that it was not the intended use of the exception,
and then saw that the author admits it.  I would go on to disagree with
the argument of using the exception as a structured goto.  An exception
is exactly that, something that is not expected to occur and if it does
is probably an error.

My initial implementation thought would be to write a boolean function
with any side effects of processing one element and returning the value
for Continue.  This perhaps comes from my C coding experiences and
probably is not good practice.

Perhaps this is an argument for an extension to the optional parameters
to include out parameters that may or may not appear in the procedure
call?  That would be an interesting implementation.

		Tim .D.
-------------------------------------------------------------------------------
Tim .D. Hammer                         BITNET: TDHAMMER@TWSUVAX
Teaching/Research Assistant            UUCP: uunet!ncrlnk!ncrwic!wsucsa!hammer
Computer Science Dept.                 INTERNET: tdhammer@wsuiar.wsu.ukans.edu
Wichita State University               TalkNET: (316)689-3156
Wichita, Ks.  67208-1595

package DISCLAIMER is
  type VIEWS is NO_ONE_ELSES ;
  subtype OPINIONS is bigoted VIEWS ;
end package DISCLAIMER ;
-------------------------------------------------------------------------------
"A little learning is a dangerous thing." Alexander Pope

madmats%elcgl.epfl.ch@VMA.CC.CMU.EDU (Mats Weber) (04/11/90)

>When I was to use the package I discovered one thing I had missed.
>There was no way to interrupt the iteration. One way is of course
>to rewrite the package so that Process_one_element should take a
>second parameter
>   Continue : OUT boolean;


Personally, I prefer to use exceptions in this case, because it is really
an EXCEPTIONal case.

But if the additonal boolean parameter is to be used, then it can be better
to make it 'in out' instead of 'out' so that if the action procedure does
not modify the parameter (or the programmer forgets to set it, which leads
to erroneous programs), iteration continues by default.

example:

   generic
      with procedure Action(X : in Item;
                            Quit : in out Boolean);
   procedure Iterate is

       Do_Quit : Boolean := False;

   begin
      loop
         ...
         Action(X, Do_Quit);
         exit when Do_Quit;
      end loop;
   end;


Mats Weber
Swiss Federal Institute of Technology
EPFL DI LGL
1015 Lausanne
Switzerland

E-mail : madmats@elcgl.epfl.ch
phone  : +41 21 693 52 92
fax    : +41 21 693 39 09

kassover@jupiter.crd.ge.com (David Kassover) (04/14/90)

In article <120.26224a7e@wsuiar.uucp> tdhammer@wsuiar.uucp writes:
...
>
>Perhaps this is an argument for an extension to the optional parameters
>to include out parameters that may or may not appear in the procedure
>call?  That would be an interesting implementation.

Would that not require that the compiler *not* verify that the
out parameter is the target of an assignment?  An important
check, no?

Perhaps an optional in out parameter, where the parameter is
guaranteed to have at least the default value would work
acceptably.


I, myself, see nothing wrong with specifying a routine that
raises an exception (and specifying the name of that exception).
Therefore one can write an exception handler to interpret the
exception as is appropriate in the outer routine.

For example:  Several routines that I use can raise the
exception FILE_NOT_FOUND.

This does not mean to me that this is an error.  In fact, the
presence of the file, and the not-raising of FILE_NOT_FOUND may
indicate that an error has occurred.

This question of "misuse" of Ada exceptions begins to remind me
of the jihad between the structured programming mullahs who
maintain that loops must be exited only in one place, and the
rest of us in the real world, who know better.


"A foolish consistency is the hobgoblin of small minds"
			-with apologies to Emerson

--
===================================================
David Kassover
kassover@ra.crd.ge.com
kassover@crd.ge.com

mfeldman@seas.gwu.edu (Mike Feldman) (04/14/90)

In article <6827@crdgw1.crd.ge.com> kassover@jupiter.crd.ge.com (David Kassover) writes:
>
>This question of "misuse" of Ada exceptions begins to remind me
>of the jihad between the structured programming mullahs who
>maintain that loops must be exited only in one place, and the
>rest of us in the real world, who know better.
>
Whoa. First, let's not get back into using inflammatory language. I think 
there are _lots_ of equally valid points of view on exceptions. The group
has calmed down and gotten back to technical stuff; I, for one, would
appreciate our all restraining ourselves from words like "jihad" and "mullah."

Now to the issue: there is a perfectly legitimate school of thought that holds
that one important purpose of the exception-raising/handling structures in
Ada is to improve readability, specifically by creating a clear visual
distinction between "normal" processing and "abnormal" (unusual, unexpected,
let's not play semantics games here) processing. Assume you belong to this   
school (I do, or I wouldn't bore you with this). You then face the question
of drawing the line, if you can, separating the normal from the abnormal.
Here is where science stops and art begins, and the line is not bright and
crisp. So there is plenty of room to discuss, like polite adults, this
essentially philosophical question.

At the two extremes are the case of popping an empty stack (clearly, at
least to me, an abnormal situation calling for an exception report) and
the case of handling CONSTRAINT_ERROR when, given a DAYS_OF_WEEK
enumeration, (MON, TUE, WED, THU, FRI, SAT, SUN), one finds tomorrow by
taking the 'SUCC of today. If today is SUN, this will obviously raise
CONSTRAINT_ERROR. Clearly, to me, handling CONSTRAINT_ERROR here is _not_
the thing to do, because MON indeed follows SUN once a week. The only thing
that makes it "abnormal" is a language idiosyncracy under which wraparound
enumerations aren't supported directly.

While handling CONSTRAINT_ERROR here is obviously permitted, I hold that
doing so dilutes the readability benefits provided by exceptions. Better to
face the language idiosyncracy directly, writing
  if today = SUN then
     tomorrow := MON
  else
     tomorrow := DAY'SUCC(today);
  end if;

I have heard it conjectured that the "extra" test in the IF statement will
lead to that ol' bugaboo, inefficiency; I haven't yet seen it proved, therefore
will assume negligible performance differences that can easily be traded away
for increased human performance. (Let me know if you have good evidence to
the contrary).

OK, so much for my two extreme cases. I happen to think that Kassover's
example is an easily justified intermediate case. Should we start a
discussion thread about other such intermediate cases? I'd find it
worthwhile unless and until it degenerates to name-calling.

By the way - I don't know of any structured-programming "mullahs" these
days. Use of new features always moves from the extremes to the middle,
as our understanding of them matures.

If a project wants to set a local coding standard - again for whatever
readability improvement they think they are after - that says "one exit
from a loop, one return from a subprogram", I think that is their privilege,
and we don't have to flame them for it. I wouldn't set such a standard
myself, but I think they have a valid viewpoint. I have seen such standards.
In industry. Is this Kassover's "real world"? I have _lots_ of friends in
the academic world; I don't think any of 'em are "mullahs."

---------------------------------------------------------------------------
Prof. Michael Feldman
Department of Electrical Engineering and Computer Science
The George Washington University
Washington, DC 20052
+1-202-994-5253
mfeldman@seas.gwu.edu
---------------------------------------------------------------------------

mfeldman@seas.gwu.edu (Mike Feldman) (05/01/90)

In article <7050@fy.sei.cmu.edu> rsd@sei.cmu.edu (Richard S D'Ippolito) writes:
>
>(*) Yes, you can define one as an ADT, and at least one inplementation of
>Pascal has the first as successor to last, but this means the bar is now the
>exception!  Isn't it better to aviod philosophical arguments as to which is
>fundamental, more useful, or prevalent, and define them both as natural
>components?
This is a nice idea. Does anyone know if there was an Ada9x suggestion to
provide this?
---------------------------------------------------------------------------
Prof. Michael Feldman
Department of Electrical Engineering and Computer Science
The George Washington University
Washington, DC 20052
+1-202-994-5253
mfeldman@seas.gwu.edu
---------------------------------------------------------------------------