comp.lang.ada
 help / color / mirror / Atom feed
* Re: Building blocks (Was: Design By Contract)
       [not found]     ` <5un58u$9ih$1@gonzo.sun3.iaf.nl>
@ 1997-09-06  0:00       ` Joachim Durchholz
  1997-09-08  0:00       ` Paul Johnson
  1 sibling, 0 replies; 74+ messages in thread
From: Joachim Durchholz @ 1997-09-06  0:00 UTC (permalink / raw)



Geert Bosch wrote:
> I find that it is often better to combine simple building blocks
> into the more complex one you need, than to use a more complex
> feature that is not exactly what you need and may be overkill. When
> combining ill-defined over-complex things like MI, C++ templates
> and exceptions, you know for sure the result will be too complex
> and not what you want.

That myth again...
MI by itself is neither complex nor ill-defined. Its C++ implementation
is. If you want to see MI How It Should Be Done, look at one of the
various Eiffel books.

On the "building blocks" argument, I agree. Of course this will work
only if language features are truly orthogonal. C++ is extremely bad in
this respect, Ada is ways better (Eiffel really shines here, one has to
actually look at the language to believe it).

Regards,
Joachim
-- 
Please don't send unsolicited ads.






^ permalink raw reply	[flat|nested] 74+ messages in thread

* Re: Building blocks (Was: Design By Contract)
  1997-09-08  0:00       ` Paul Johnson
@ 1997-09-08  0:00         ` Brian Rogoff
  1997-09-09  0:00           ` Matthew Heaney
                             ` (3 more replies)
  0 siblings, 4 replies; 74+ messages in thread
From: Brian Rogoff @ 1997-09-08  0:00 UTC (permalink / raw)



On 8 Sep 1997, Paul Johnson wrote:
> Please don't judge a language feature (*any* feature) by its implementation
> in C++.  The language is a bodge.

If you read comp.lang.ada, you might learn that some people find certain
aspects of C++ interesting, perhaps even worthy of being considered for 
inclusion in a future Ada :-). I suggest that you abandon your programming
language religion when posting to multiple children of comp.lang. 

> Take a look at Eiffel instead.  

I have. And I used Sather for quite a while too. I find Ada superior to
both, though I confess that I find Sather iterators extremely elegant and 
more importantly I wish garbage collection was the "default" for Ada.
I think the module-type conflation is really confusion, and that OO is not 
the uber-paradigm which subsumes all others. 

> And if you do it in C++ I'd agree with you.  However in Eiffel you will
> find that MI, templates and exceptions all fit together in a unified
> whole.  In fact the Eiffel exception mechanism is superior to the Ada one
> because it is built on a theoretical model of software engineering.

I find it rather funny that in one post you say you don't use Ada, and
can't understand the idioms for doing MI in Ada, but somehow you just
"know" that it is a fact that the Eiffel exception mechanism is superior 
to Ada's. Ada exceptions can do everything Eiffel's can and more. (And
before that "goto" vs "structured" analogy gets going, I find the extra 
power useful).

Eiffel's inheritance is based on a theoretical model which later turned out 
to be unsafe. A (theoretical) fix was proposed, and never implemented. And
now we have another theoretical fix. So much for Eiffel theoretical
models! :-)

-- Brian






^ permalink raw reply	[flat|nested] 74+ messages in thread

* Re: Building blocks (Was: Design By Contract)
       [not found]     ` <5un58u$9ih$1@gonzo.sun3.iaf.nl>
  1997-09-06  0:00       ` Building blocks (Was: Design By Contract) Joachim Durchholz
@ 1997-09-08  0:00       ` Paul Johnson
  1997-09-08  0:00         ` Brian Rogoff
  1 sibling, 1 reply; 74+ messages in thread
From: Paul Johnson @ 1997-09-08  0:00 UTC (permalink / raw)



In article <5un58u$9ih$1@gonzo.sun3.iaf.nl>, geert@gonzo.sun3.iaf.nl says...

>Paul Johnson <paul.johnson@gecm.com> wrote:

[On language features versus idiomatic programming]

>   For example Eiffel has direct support for multiple inheritance
>   (MI).  Ada requires you to play games with generic parameters
>   in order to achieve the same effect.''
>
>I find that it is often better to combine simple building blocks
>into the more complex one you need, than to use a more complex
>feature that is not exactly what you need and may be overkill.

[Experiences based on Ada versus C++ omitted]

Please don't judge a language feature (*any* feature) by its implementation
in C++.  The language is a bodge.

Take a look at Eiffel instead.  

> When
> combining ill-defined over-complex things like MI, C++ templates
> and exceptions, you know for sure the result will be too complex
> and not what you want.

And if you do it in C++ I'd agree with you.  However in Eiffel you will
find that MI, templates and exceptions all fit together in a unified
whole.  In fact the Eiffel exception mechanism is superior to the Ada one
because it is built on a theoretical model of software engineering.

Paul.

-- 
Paul Johnson            | GEC-Marconi Ltd is not responsible for my opinions. |
+44 1245 242244         +-----------+-----------------------------------------+
Work: <paul.johnson@gecm.com>       | You are lost in a twisty maze of little
Home: <Paul@treetop.demon.co.uk>    | standards, all different.





^ permalink raw reply	[flat|nested] 74+ messages in thread

* Re: Building blocks (Was: Design By Contract)
@ 1997-09-09  0:00 Marc Wachowitz
  1997-09-15  0:00 ` Joachim Durchholz
  1997-09-17  0:00 ` Paul Johnson
  0 siblings, 2 replies; 74+ messages in thread
From: Marc Wachowitz @ 1997-09-09  0:00 UTC (permalink / raw)



paul.johnson@gecm.com (Paul Johnson) wrote:
> In fact the Eiffel exception mechanism is superior to the Ada one
> because it is built on a theoretical model of software engineering.

It is only "superior" if you think that Bertrand Meyer's proposed theory
about exceptions is the only valid one. I don't think it is - and just to
the contrary, I consider something like Eiffel's class EXCEPTION an ugly
hack to differentiate between kinds of exceptions.

In fact, I think Common Lisp, and later C++ and Java, got it right with
using subtyping as a means to differentiate between exception objects and
to associate information with exceptions; likewise, as in Modula-3 and
Java (similarly C++, as far as I know), I'd like to have a classification
of the possible exceptions raised by a routine in its declaration. Lacking
that, Ada's solution is still far superiour to Eiffel's approach, in my
view.

-- Marc Wachowitz <mw@ipx2.rz.uni-mannheim.de>




^ permalink raw reply	[flat|nested] 74+ messages in thread

* Re: Building blocks (Was: Design By Contract)
  1997-09-09  0:00           ` Matthew Heaney
@ 1997-09-09  0:00             ` Brian Rogoff
  1997-09-09  0:00             ` W. Wesley Groleau x4923
                               ` (2 subsequent siblings)
  3 siblings, 0 replies; 74+ messages in thread
From: Brian Rogoff @ 1997-09-09  0:00 UTC (permalink / raw)



On Tue, 9 Sep 1997, Matthew Heaney wrote:

> In article <Pine.SGI.3.95.970908193446.11288B-100000@shellx.best.com>,
> Brian Rogoff <bpr@shellx.best.com> wrote:
> 
> >>In fact the Eiffel exception mechanism is superior to the Ada one
> >> because it is built on a theoretical model of software engineering.

Watch your attributions, I didn't write that!

> Can any of the Eiffel guys explain this a bit more?  I'm curious what is
> meant by a "theoretical model of software engineering."  Can someone post
> some references to the theory behind the Eiffel exception mechanism?

The original poster probably meant that the Eiffel exception mechanism was 
designed to support Eiffel design by contract, so that when an exception is 
raised you retry or fail, restoring class invariants on leaving. I doubt he 
was talking about denotational semantics or theoretical models like that!

You can read about DBC in Meyer's book or one of the many articles he's 
written. 

-- Brian






^ permalink raw reply	[flat|nested] 74+ messages in thread

* Re: Building blocks (Was: Design By Contract)
@ 1997-09-09  0:00 Marc Wachowitz
  0 siblings, 0 replies; 74+ messages in thread
From: Marc Wachowitz @ 1997-09-09  0:00 UTC (permalink / raw)



mheaney@ni.net (Matthew Heaney) wrote:
> I've always been curious about the semantics of exception propagation,
> because it doesn't correspond to anything in pure math (or does it?).  If I
> divide x by 0 on paper, I can strug my shoulders and say, "Oh well,
> division by 0 isn't defined," but on a computer, I have to do _something_. 

That's easy. All functions (or generally procedures, or any statements and
expressions) can be seen as mappings from one state to another, and among
the possible outcomes of a such functions are the "normal outcome", where no
exception was raised, and some "abnormal outcome" (possibly indicating the
detailed cause for the exception as well, whether just with a name, or with
additional data, like the error code of some system call). In the area of
applicative languages, and the associated theory, there's even something
known as continuation-passing style, where any sequence of computation is
made explicit by passing to every function another function, the so-called
continuation, which is invoked with the result of the former function. Then
control structure manifests as a choice between many possible continuations.
You could model the dynamic nesting of exception handlers by passing to each
function (in the general sense; i.e. also expressions/statements) both a
continuation for normal cases and a continuation for exceptional cases, and
functions without any own exception handlers would pass along whatever they
received as their exception-continuation. When an exception handler doesn't
propagate the exception, that means that it invokes the appropriate normal
continuation of its own context.

In Scheme (a Lisp dialect), continuations are even available to programmers
and can be used to model a variety of other control structures, including
exceptions, but also backtracking or coroutines. (For detailed background,
I suggest you ask on comp.lang.scheme about these things; there are people
who can probably give you better references to books or papers on the net
than the little I'd have available.)

-- Marc Wachowitz <mw@ipx2.rz.uni-mannheim.de>




^ permalink raw reply	[flat|nested] 74+ messages in thread

* Re: Building blocks (Was: Design By Contract)
  1997-09-08  0:00         ` Brian Rogoff
@ 1997-09-09  0:00           ` Matthew Heaney
  1997-09-09  0:00             ` Brian Rogoff
                               ` (3 more replies)
  1997-09-09  0:00           ` W. Wesley Groleau x4923
                             ` (2 subsequent siblings)
  3 siblings, 4 replies; 74+ messages in thread
From: Matthew Heaney @ 1997-09-09  0:00 UTC (permalink / raw)




In article <Pine.SGI.3.95.970908193446.11288B-100000@shellx.best.com>,
Brian Rogoff <bpr@shellx.best.com> wrote:

>>In fact the Eiffel exception mechanism is superior to the Ada one
>> because it is built on a theoretical model of software engineering.

Can any of the Eiffel guys explain this a bit more?  I'm curious what is
meant by a "theoretical model of software engineering."  Can someone post
some references to the theory behind the Eiffel exception mechanism?

I've always been curious about the semantics of exception propagation,
because it doesn't correspond to anything in pure math (or does it?).  If I
divide x by 0 on paper, I can strug my shoulders and say, "Oh well,
division by 0 isn't defined," but on a computer, I have to do _something_. 


I just finished the Gordon book on denotational semantics, and even he just
sort of says "return {error}"; maybe the Stoy book has something more.

I read the Luckham paper, and he presented the idea that an assertion be
associated with each exception raised by a subprogram, to describe the
state when the exception is propagated.

It would be cool if you could check at compile time that all exceptions
were being handled by the client, and that only the exceptions advertised
by a supplier get raised (and only in the specified state).  Maybe that's
the Eiffel model already.

--------------------------------------------------------------------
Matthew Heaney
Software Development Consultant
<mailto:matthew_heaney@acm.org>
(818) 985-1271




^ permalink raw reply	[flat|nested] 74+ messages in thread

* Re: Building blocks (Was: Design By Contract)
  1997-09-08  0:00         ` Brian Rogoff
  1997-09-09  0:00           ` Matthew Heaney
  1997-09-09  0:00           ` W. Wesley Groleau x4923
@ 1997-09-09  0:00           ` Veli-Pekka Nousiainen
  1997-09-09  0:00             ` Jon S Anthony
  1997-09-09  0:00           ` Veli-Pekka Nousiainen
  3 siblings, 1 reply; 74+ messages in thread
From: Veli-Pekka Nousiainen @ 1997-09-09  0:00 UTC (permalink / raw)



Unsafe? what is unsafe in Eiffel inheritance? And what is the fix? 
I have joined in much too late... 
VP 

Brian Rogoff <bpr@shellx.best.com> wrote in article
<Pine.SGI.3.95.970908193446.11288B-100000@shellx.best.com>...
<SNIP> 
> Eiffel's inheritance is based on a theoretical model which later turned
out 
> to be unsafe. A (theoretical) fix was proposed, and never implemented.
And
> now we have another theoretical fix. So much for Eiffel theoretical
> models! :-)
> 
> -- Brian
> 




^ permalink raw reply	[flat|nested] 74+ messages in thread

* Re: Building blocks (Was: Design By Contract)
  1997-09-08  0:00         ` Brian Rogoff
                             ` (2 preceding siblings ...)
  1997-09-09  0:00           ` Veli-Pekka Nousiainen
@ 1997-09-09  0:00           ` Veli-Pekka Nousiainen
  3 siblings, 0 replies; 74+ messages in thread
From: Veli-Pekka Nousiainen @ 1997-09-09  0:00 UTC (permalink / raw)



Unsafe? what is unsafe in Eiffel inheritance? And what is the fix? 
I have joined in much too late... 
VP 

Brian Rogoff <bpr@shellx.best.com> wrote in article
<Pine.SGI.3.95.970908193446.11288B-100000@shellx.best.com>...
<SNIP> 
> Eiffel's inheritance is based on a theoretical model which later turned
out 
> to be unsafe. A (theoretical) fix was proposed, and never implemented.
And
> now we have another theoretical fix. So much for Eiffel theoretical
> models! :-)
> 
> -- Brian
> 




^ permalink raw reply	[flat|nested] 74+ messages in thread

* Re: Building blocks (Was: Design By Contract)
  1997-09-09  0:00           ` Veli-Pekka Nousiainen
@ 1997-09-09  0:00             ` Jon S Anthony
  0 siblings, 0 replies; 74+ messages in thread
From: Jon S Anthony @ 1997-09-09  0:00 UTC (permalink / raw)




In article <01bcbd1d$72196760$108142c1@Yeif-1.eiffel.fi> "Veli-Pekka Nousiainen" <vp.nousiainen@remove_this_eiffel.fi> writes:

> Unsafe? what is unsafe in Eiffel inheritance? And what is the fix? 
> I have joined in much too late... 
> VP 

The polymorphic "CAT call" stuff, which rests ultimately on covariance
which is one of the basic tenets underlying Eiffel's inheritance
model.

/Jon

> Brian Rogoff <bpr@shellx.best.com> wrote in article
> <Pine.SGI.3.95.970908193446.11288B-100000@shellx.best.com>...
> <SNIP> 
> > Eiffel's inheritance is based on a theoretical model which later turned
> out 
> > to be unsafe. A (theoretical) fix was proposed, and never implemented.
> And
> > now we have another theoretical fix. So much for Eiffel theoretical
> > models! :-)
> > 
> > -- Brian
> > 
-- 
Jon Anthony
OMI, Belmont, MA 02178, 617.484.3383 
"Nightmares - Ha!  The way my life's been going lately,
 Who'd notice?"  -- Londo Mollari




^ permalink raw reply	[flat|nested] 74+ messages in thread

* Re: Building blocks (Was: Design By Contract)
  1997-09-08  0:00         ` Brian Rogoff
  1997-09-09  0:00           ` Matthew Heaney
@ 1997-09-09  0:00           ` W. Wesley Groleau x4923
  1997-09-09  0:00           ` Veli-Pekka Nousiainen
  1997-09-09  0:00           ` Veli-Pekka Nousiainen
  3 siblings, 0 replies; 74+ messages in thread
From: W. Wesley Groleau x4923 @ 1997-09-09  0:00 UTC (permalink / raw)




> > whole.  In fact the Eiffel exception mechanism is superior to the 
> > Ada one because it is built on a theoretical model of software 
> > engineering.

Theory is a good thing when it leads to progress.  After it is 
confirmed by practical experience, it remains a good thing.
As soon as it disagrees with practical experience, it becomes
a Bad Thing.

Ada's design had plenty of "theory" behind it.  But it also had
plenty of experienced people to shoot down any tendency to put
excessive faith in theory.

I can't personally say Eiffel's experience supports or disproves
its theory.  (Obviously, there are plenty of people already saying
it supports it.)  But I can say that "built on a theoretical model"
is certainly no argument for superiority over Ada, or even over C.

To change a word in an earlier quote:
"A man with an experience is never at the mercy of
 a man with a theory."

-- 
----------------------------------------------------------------------
    Wes Groleau, Hughes Defense Communications, Fort Wayne, IN USA
Senior Software Engineer - AFATDS                  Tool-smith Wanna-be
                    wwgrol AT pseserv3.fw.hac.com

Don't send advertisements to this domain unless asked!  All disk space
on fw.hac.com hosts belongs to either Hughes Defense Communications or 
the United States government.  Using email to store YOUR advertising 
on them is trespassing!
----------------------------------------------------------------------




^ permalink raw reply	[flat|nested] 74+ messages in thread

* Re: Building blocks (Was: Design By Contract)
  1997-09-09  0:00           ` Matthew Heaney
  1997-09-09  0:00             ` Brian Rogoff
@ 1997-09-09  0:00             ` W. Wesley Groleau x4923
  1997-09-10  0:00               ` Robert A Duff
  1997-09-10  0:00             ` Robert Dewar
  1997-09-10  0:00             ` Paul Johnson
  3 siblings, 1 reply; 74+ messages in thread
From: W. Wesley Groleau x4923 @ 1997-09-09  0:00 UTC (permalink / raw)



> It would be cool if you could check at compile time that all exceptions
> were being handled by the client, and that only the exceptions advertised
> by a supplier get raised (and only in the specified state).  Maybe that's
> the Eiffel model already.

Well, that's one good thing you can say about Java.  Or is it (good)?

-- 
----------------------------------------------------------------------
    Wes Groleau, Hughes Defense Communications, Fort Wayne, IN USA
Senior Software Engineer - AFATDS                  Tool-smith Wanna-be
                    wwgrol AT pseserv3.fw.hac.com

Don't send advertisements to this domain unless asked!  All disk space
on fw.hac.com hosts belongs to either Hughes Defense Communications or 
the United States government.  Using email to store YOUR advertising 
on them is trespassing!
----------------------------------------------------------------------




^ permalink raw reply	[flat|nested] 74+ messages in thread

* Re: Building blocks (Was: Design By Contract)
  1997-09-10  0:00             ` Paul Johnson
  1997-09-10  0:00               ` Darren New
@ 1997-09-10  0:00               ` Matthew Heaney
  1 sibling, 0 replies; 74+ messages in thread
From: Matthew Heaney @ 1997-09-10  0:00 UTC (permalink / raw)



In article <5v5l26$h62$3@miranda.gmrc.gecm.com>, paul.johnson@gecm.com
(Paul Johnson) wrote:


>In Ada exceptions seem to be treated as a sort of out-of-band enumerated
>type.

It depends on the programmer - I have have seen many of the abuses you
describe.  However, I personally use Ada exceptions exactly as you
recommend.

--------------------------------------------------------------------
Matthew Heaney
Software Development Consultant
<mailto:matthew_heaney@acm.org>
(818) 985-1271




^ permalink raw reply	[flat|nested] 74+ messages in thread

* Re: Building blocks (Was: Design By Contract)
  1997-09-10  0:00             ` Paul Johnson
@ 1997-09-10  0:00               ` Darren New
  1997-09-10  0:00               ` Matthew Heaney
  1 sibling, 0 replies; 74+ messages in thread
From: Darren New @ 1997-09-10  0:00 UTC (permalink / raw)



>Note that there is no third option.  Also note that the following are
>forbidden:
>
>* Silent failure.  If the server cannot fulfil its contract then it *must*
>  raise an exception.
>
>* Exceptions as normal control structure.  An exception indicates that
>  something has gone wrong: things are not working as intended. 

Elaborating: Actually, I think the theoretical basis for the exceptions
are that you cannot catch an exception and continue on. For example,
if your calling code says

  x := him.blah(y)
  fooble(x)

then if him.blah has a postcondition that Result>0, fooble can rely
on getting an argument whose value is > 0.  If him.blah fails to
return the value that meets the postcondition, an exception is raised
and passed to the caller. Hence, it is *impossible* to call fooble
here with a negative value for x.  There is no equivalent of
  try { x := him.blah(y) } catch (...) { /* do nothing */ }
  fooble(x)

If every line of code does not fulfill its postconditions, it's impossible
to execute the following line. And *that* I believe is what makes
the exception mechanism helpful in reasoning about your code.

Of course, it's also helpful that you do not have to catch errors in
the wrong place.  I very much dislike the Java mechanism when I try
to implement an interface that does not throw IOException (for example)
and I'm doing IO, so I have to figure out what the client is likely
to want in terms of error handling, making reuse difficult. There are
ways around it, but it's kludgey.
  -- Darren





^ permalink raw reply	[flat|nested] 74+ messages in thread

* Re: Building blocks (Was: Design By Contract)
  1997-09-09  0:00           ` Matthew Heaney
  1997-09-09  0:00             ` Brian Rogoff
  1997-09-09  0:00             ` W. Wesley Groleau x4923
@ 1997-09-10  0:00             ` Robert Dewar
  1997-09-12  0:00               ` Paul Johnson
  1997-09-12  0:00               ` Jon S Anthony
  1997-09-10  0:00             ` Paul Johnson
  3 siblings, 2 replies; 74+ messages in thread
From: Robert Dewar @ 1997-09-10  0:00 UTC (permalink / raw)



Brian Rogoff said

<<>>In fact the Eiffel exception mechanism is superior to the Ada one
>> because it is built on a theoretical model of software engineering.>>

This is one of the more absurd statements in what is unfortunately becoming
a rather tedious thread. First of all, the idea that being "built on
*a* (i.e. any old) theoretical model of software engineering" is per se
a good thing is a bit laughable.

Second, of course the Ada exception mechanism is build on such a model
also -- indeed it *is* a model itself!

Rather thank make vague religeous statements like this which have 
zero meaning, say EXACTLY what technical point you are trying to make.





^ permalink raw reply	[flat|nested] 74+ messages in thread

* Re: Building blocks (Was: Design By Contract)
  1997-09-09  0:00             ` W. Wesley Groleau x4923
@ 1997-09-10  0:00               ` Robert A Duff
  1997-09-12  0:00                 ` Jon S Anthony
  0 siblings, 1 reply; 74+ messages in thread
From: Robert A Duff @ 1997-09-10  0:00 UTC (permalink / raw)



In article <3415BA96.19B1@pseserv3.fw.hac.com>,
W. Wesley Groleau x4923 <wwgrol@pseserv3.fw.hac.com> wrote:
>
>> It would be cool if you could check at compile time that all exceptions
>> were being handled by the client, and that only the exceptions advertised
>> by a supplier get raised (and only in the specified state).  Maybe that's
>> the Eiffel model already.
>
>Well, that's one good thing you can say about Java.  Or is it (good)?

No, it's not good.  It leads to "crying wolf" -- that is, one must state
that so-and-so might raise such-and-such exception, even when it's
obvious it won't.  Consider, for example, the stream classes in Java.  A
stream that represents a sequence of bytes read from an in-memory array
has to falsely state that it might raise various I/O related exceptions,
despite the fact that it has nothing whatsoever to do with I/O.

The sentiment here is good, but it doesn't work given the paricular
rules of Java, IMHO.  Perhaps a different set of language rules could
achieve the benefits without the "crying wolf" problems.

- Bob




^ permalink raw reply	[flat|nested] 74+ messages in thread

* Re: Building blocks (Was: Design By Contract)
  1997-09-09  0:00           ` Matthew Heaney
                               ` (2 preceding siblings ...)
  1997-09-10  0:00             ` Robert Dewar
@ 1997-09-10  0:00             ` Paul Johnson
  1997-09-10  0:00               ` Darren New
  1997-09-10  0:00               ` Matthew Heaney
  3 siblings, 2 replies; 74+ messages in thread
From: Paul Johnson @ 1997-09-10  0:00 UTC (permalink / raw)




In article <mheaney-ya023680000909970121270001@news.ni.net>, mheaney@ni.net 
says...

>In article <Pine.SGI.3.95.970908193446.11288B-100000@shellx.best.com>,
>Brian Rogoff <bpr@shellx.best.com> wrote:

>>>In fact the Eiffel exception mechanism is superior to the Ada one
>>> because it is built on a theoretical model of software engineering.

Brian Rogoff didn't write that, I did.

>Can any of the Eiffel guys explain this a bit more?  I'm curious what is
>meant by a "theoretical model of software engineering."  Can someone post
>some references to the theory behind the Eiffel exception mechanism?

I was referring to "design by contract", which underpins pretty much the
whole of Eiffel.  See OOSC-2 for the fullest explanation yet.  E:TL also
has quite a lot of stuff about it, and the theory was laid out in OOSC-1
in enough detail for a first pass.  I think that there is also an outline
on the ISE web site (www.eiffel.com).

>I've always been curious about the semantics of exception propagation,
>because it doesn't correspond to anything in pure math (or does it?).

Under DbC, the server class offers a "contract" specified by the
preconditions, postconditions and invariants.  When a routine is called,
the client must fulfil the preconditions (otherwise there is a bug in
the client).  Once these preconditions are fulfilled the server class
must either fulfil the postconditions and invariants *or* raise an
exception.  In everyday programming this just means that it must fulfil
its postconditions and invariants, but for instance an RPC mechanism
might trigger an exception if it discovers that the network is down.

Once an exception has been triggered the class has two options:

1. Tidy up any internal state and pass the exception back to the caller.

2. Try again, possibly using a different stratagy.

Note that there is no third option.  Also note that the following are
forbidden:

* Silent failure.  If the server cannot fulfil its contract then it *must*
  raise an exception.

* Exceptions as normal control structure.  An exception indicates that
  something has gone wrong: things are not working as intended.  It might
  be that the "something" is outside the software's control (e.g. network
  down) and the software has been written to handle this gracefully, but
  there is still something wrong.  A dictionary lookup routine does not
  return an exception if it fails to find an entry.

>It would be cool if you could check at compile time that all exceptions
>were being handled by the client, and that only the exceptions advertised
>by a supplier get raised (and only in the specified state).  Maybe that's
>the Eiffel model already.

In Eiffel there is not much distinction between exceptions.  You can
examine an exception, but thats more so you can put something useful 
in the error log than for any control-flow reasons.  As far as control
flow is concerned, the key fact is that the routine has failed.  Nothing
else matters.

In Ada exceptions seem to be treated as a sort of out-of-band enumerated
type.

Paul.

-- 
Paul Johnson            | GEC-Marconi Ltd is not responsible for my opinions. |
+44 1245 242244         +-----------+-----------------------------------------+
Work: <paul.johnson@gecm.com>       | You are lost in a twisty maze of little
Home: <Paul@treetop.demon.co.uk>    | standards, all different.





^ permalink raw reply	[flat|nested] 74+ messages in thread

* Re: Building blocks (Was: Design By Contract)
@ 1997-09-11  0:00 Robert Dewar
  0 siblings, 0 replies; 74+ messages in thread
From: Robert Dewar @ 1997-09-11  0:00 UTC (permalink / raw)



Brian Rogoff complained, quite rightly, to me as quoted below. Sorry for
the mistake in attributions, it is often easy to get confused, and especially
to borrow confusion. Too bad this is not all automated :-)

--
Brian's msg:

Please be careful with attributions, I never wrote that, that was Paul
Johnson! I wrote a rebuttal that Matthew Heaney carelessly edited in his
own follow-up.

-- Brian

On 10 Sep 1997, Robert Dewar wrote:

> Brian Rogoff said
>
> <<>>In fact the Eiffel exception mechanism is superior to the Ada one
> >> because it is built on a theoretical model of software engineering.>>
>
> This is one of the more absurd statements in what is unfortunately becoming
> a rather tedious thread. First of all, the idea that being "built on
> *a* (i.e. any old) theoretical model of software engineering" is per se
> a good thing is a bit laughable.
>
> Second, of course the Ada exception mechanism is build on such a model
> also -- indeed it *is* a model itself!
>
> Rather thank make vague religeous statements like this which have
> zero meaning, say EXACTLY what technical point you are trying to make.









^ permalink raw reply	[flat|nested] 74+ messages in thread

* Re: Building blocks (Was: Design By Contract)
  1997-09-12  0:00               ` Jon S Anthony
@ 1997-09-12  0:00                 ` Robert Dewar
  1997-09-16  0:00                   ` Brian Rogoff
  0 siblings, 1 reply; 74+ messages in thread
From: Robert Dewar @ 1997-09-12  0:00 UTC (permalink / raw)



Jon said

<<> Brian Rogoff said
>
> <<>>In fact the Eiffel exception mechanism is superior to the Ada one
> >> because it is built on a theoretical model of software engineering.>>
>
> This is one of the more absurd statements in what is unfortunately becoming
> a rather tedious thread. First of all, the idea that being "built on
> *a* (i.e. any old) theoretical model of software engineering" is per se
> a good thing is a bit laughable.

Coming to Brian's defense here: He didn't say this, Paul Johnson said
it.  However, I fully agree with your characterization of the statement.>>


Gosh, another horrible attribution error, that's twice in a week. Sorry
about that Brian!





^ permalink raw reply	[flat|nested] 74+ messages in thread

* Re: Building blocks (Was: Design By Contract)
  1997-09-10  0:00             ` Robert Dewar
@ 1997-09-12  0:00               ` Paul Johnson
  1997-09-14  0:00                 ` Robert Dewar
                                   ` (2 more replies)
  1997-09-12  0:00               ` Jon S Anthony
  1 sibling, 3 replies; 74+ messages in thread
From: Paul Johnson @ 1997-09-12  0:00 UTC (permalink / raw)



In article <dewar.873938975@merv>, Robert Dewar <dewar@merv.cs.nyu.edu>
writes
>Brian Rogoff said
>
><<>>In fact the Eiffel exception mechanism is superior to the Ada one
>>> because it is built on a theoretical model of software engineering.>>

As someone else pointed out, I said that, not Brian.

>This is one of the more absurd statements in what is unfortunately becoming
>a rather tedious thread. First of all, the idea that being "built on
>*a* (i.e. any old) theoretical model of software engineering" is per se
>a good thing is a bit laughable.

In the original posting I was trying to be brief.  I have since
explained about design by contract and the Eiffel exception mechanism.

>Second, of course the Ada exception mechanism is build on such a model
>also -- indeed it *is* a model itself!

If I understand you correctly, the Ada exception mechanism looks like it
does because that was how the designers designed it.  My original point
was that the Eiffel mechanism looks like it does because the theory of
software contracting required it to work that way.

Actually I don't believe that the Ada designers just threw together its
exception mechanism without thinking long and hard, and I don't think
you really meant to imply it.  However the lack of an underlying theory
on its use and contribution to program correctness definitely shows up.
Ada exceptions seem to have been designed as a way of unwinding the
execution stack without letting the programmer break the language.  The
only reason for including it in the language was that programmers often
want to do this.

Paul.

--------------------------------+---------------------------------
Paul Johnson                    | You are lost in a maze of twisty
Email: Paul@treetop.demon.co.uk | little standards, all different.
       paul.johnson@gecm.com    |




^ permalink raw reply	[flat|nested] 74+ messages in thread

* Re: Building blocks (Was: Design By Contract)
  1997-09-10  0:00             ` Robert Dewar
  1997-09-12  0:00               ` Paul Johnson
@ 1997-09-12  0:00               ` Jon S Anthony
  1997-09-12  0:00                 ` Robert Dewar
  1 sibling, 1 reply; 74+ messages in thread
From: Jon S Anthony @ 1997-09-12  0:00 UTC (permalink / raw)




In article <dewar.873938975@merv> dewar@merv.cs.nyu.edu (Robert Dewar) writes:

> Brian Rogoff said
> 
> <<>>In fact the Eiffel exception mechanism is superior to the Ada one
> >> because it is built on a theoretical model of software engineering.>>
> 
> This is one of the more absurd statements in what is unfortunately becoming
> a rather tedious thread. First of all, the idea that being "built on
> *a* (i.e. any old) theoretical model of software engineering" is per se
> a good thing is a bit laughable.

Coming to Brian's defense here: He didn't say this, Paul Johnson said
it.  However, I fully agree with your characterization of the statement.


/Jon
-- 
Jon Anthony
OMI, Belmont, MA 02178, 617.484.3383 
"Nightmares - Ha!  The way my life's been going lately,
 Who'd notice?"  -- Londo Mollari




^ permalink raw reply	[flat|nested] 74+ messages in thread

* Re: Building blocks (Was: Design By Contract)
  1997-09-10  0:00               ` Robert A Duff
@ 1997-09-12  0:00                 ` Jon S Anthony
  0 siblings, 0 replies; 74+ messages in thread
From: Jon S Anthony @ 1997-09-12  0:00 UTC (permalink / raw)




In article <EG9ruK.BIq@world.std.com> bobduff@world.std.com (Robert A Duff) writes:

> >> It would be cool if you could check at compile time that all exceptions
> >> were being handled by the client, and that only the exceptions advertised
> >> by a supplier get raised (and only in the specified state).  Maybe that's
> >> the Eiffel model already.
> >
> >Well, that's one good thing you can say about Java.  Or is it (good)?
> 
> No, it's not good.  It leads to "crying wolf" -- that is, one must state
> that so-and-so might raise such-and-such exception, even when it's
> obvious it won't.  Consider, for example, the stream classes in Java.  A
> stream that represents a sequence of bytes read from an in-memory array
> has to falsely state that it might raise various I/O related exceptions,
> despite the fact that it has nothing whatsoever to do with I/O.
> 
> The sentiment here is good, but it doesn't work given the paricular
> rules of Java, IMHO.  Perhaps a different set of language rules could
> achieve the benefits without the "crying wolf" problems.

CORBA IDL has this same problem.  Actually, it may have influenced the
Java model as it certainly came B4 Java (I wonder if this bit of IDL
can be traced back to Sun....)

/Jon

-- 
Jon Anthony
OMI, Belmont, MA 02178, 617.484.3383 
"Nightmares - Ha!  The way my life's been going lately,
 Who'd notice?"  -- Londo Mollari




^ permalink raw reply	[flat|nested] 74+ messages in thread

* Re: Building blocks (Was: Design By Contract)
  1997-09-12  0:00               ` Paul Johnson
@ 1997-09-14  0:00                 ` Robert Dewar
  1997-09-14  0:00                 ` Robert Dewar
  1997-09-14  0:00                 ` Robert Dewar
  2 siblings, 0 replies; 74+ messages in thread
From: Robert Dewar @ 1997-09-14  0:00 UTC (permalink / raw)



<<If I understand you correctly, the Ada exception mechanism looks like it
does because that was how the designers designed it.  My original point
was that the Eiffel mechanism looks like it does because the theory of
software contracting required it to work that way.>>

No, that is completely wrong, and if you want to find out why you are
wrong, you should read the Ada Rationale. 





^ permalink raw reply	[flat|nested] 74+ messages in thread

* Re: Building blocks (Was: Design By Contract)
  1997-09-12  0:00               ` Paul Johnson
  1997-09-14  0:00                 ` Robert Dewar
  1997-09-14  0:00                 ` Robert Dewar
@ 1997-09-14  0:00                 ` Robert Dewar
  2 siblings, 0 replies; 74+ messages in thread
From: Robert Dewar @ 1997-09-14  0:00 UTC (permalink / raw)




Paul said

<<Actually I don't believe that the Ada designers just threw together its
exception mechanism without thinking long and hard, and I don't think
you really meant to imply it.  However the lack of an underlying theory
on its use and contribution to program correctness definitely shows up.
Ada exceptions seem to have been designed as a way of unwinding the
execution stack without letting the programmer break the language.  The
only reason for including it in the language was that programmers often
want to do this.
>>


No need to believe or not believe anything here (actually you really use
believe as a synonym for guess, but there is no need to guess). if you
want to make statements about Ada Exception handling which you expect any
one to pay attention to, do a little homework. And in particular, study
the extensive material that is available to answer your question without
guesses (your "seems to have been designed" is complete nonsense, as you
will see if you do this homework!)





^ permalink raw reply	[flat|nested] 74+ messages in thread

* Re: Building blocks (Was: Design By Contract)
  1997-09-12  0:00               ` Paul Johnson
  1997-09-14  0:00                 ` Robert Dewar
@ 1997-09-14  0:00                 ` Robert Dewar
  1997-09-15  0:00                   ` John G. Volan
  1997-09-14  0:00                 ` Robert Dewar
  2 siblings, 1 reply; 74+ messages in thread
From: Robert Dewar @ 1997-09-14  0:00 UTC (permalink / raw)



<<In the original posting I was trying to be brief.  I have since
explained about design by contract and the Eiffel exception mechanism.>>

It is not at all the case that the abstract notion of design by contract
dictates the design of the detailed syntax of the exception mechanism.
Of course (as anyone familiar with the Ada design process are very aware),
the Ada design of specifications is entirely focussed on the issue of what
elements of the interface contract belong in the syntax of the language and
what are best left to comments. The same statement can of course be made
in Eiffel, so the theoretical bases, or more accurately, the fundamental
design principles, are in fact very similar.

The specific issue in Ada of whether it should be part of the syntax of
the language to specify the exceptions that can be raised is of course
one that was extensively discussed, and the quite deliberate decision was
made that it is unhelpful to require these to be stated in the syntax.

The reason is that there are too many exceptions (Storage_Error, or the
various IO errors if any IO is done, or other application defined system
wide exceptions) which would be named all over the place and create clutter.
Note that Program_Error would also have to be named almost everwhere because
of the Access Before Elaboration (ABE) considerations.

SO there is no question of a presence or lack of theory here, rather it is
a pragmatic issue of what should and should not go into the syntactical
interface. Eiffel generally decides to put more into the syntax, but there
is no real evidence to suggest that this is a good thing, it's mostly a
subjective issue.





^ permalink raw reply	[flat|nested] 74+ messages in thread

* Re: Building blocks (Was: Design By Contract)
  1997-09-09  0:00 Building blocks (Was: Design By Contract) Marc Wachowitz
@ 1997-09-15  0:00 ` Joachim Durchholz
  1997-09-17  0:00 ` Paul Johnson
  1 sibling, 0 replies; 74+ messages in thread
From: Joachim Durchholz @ 1997-09-15  0:00 UTC (permalink / raw)



Marc Wachowitz wrote:
> ...I consider something like Eiffel's class EXCEPTION an ugly
> hack to differentiate between kinds of exceptions.

Indeed it is. Mimicking Java's elaborate I/O exception hierarchy would
be a nightmare.

However, exceptions don't have to serve as many purposes in Eiffel as in
Java.

First of all, Eiffel is designed for side-effect-free functions. A
subroutine is either a command (procedure, function with void return
type) that may change the externally perceivable state of an object. Or
it is a query (function, function with non-void return type) that allows
us to perceive the state of the object.
This means file I/O (to most plentiful source of exceptions I think)
works totally different than in Java or C. There is no getchar()
function, which would change the state of the associated FILE object
*and* return a value. Instead, you can have a get_file_block(from,to)
procedure that tries to read the bytes in the given from..to range; if
an I/O error occurs, the FILE object takes note of the error. Nothing
else is done in get_file_block; however, FILE also offers a set of
queries to determine wether the last access was successful, failure
reasons if not, access to data as far as it could be read, etc. etc.

What remains for exception handling are two sources:
1) Truly unexpected stuff, which is traditionally reported with the
prefix "This can't happen:". There isn't much that can be done about
such events - a human must look at the message and decide what to do -
which EXCEPTION will readily handle.
2) There are a few operations where checking wether they will work
before calling them is as expensive as running the operation. Typical
examples are arithmetic overflow conditions and matrix inversions. In
these cases, the exceptions are raised at the call and should be handled
immediately after the call. Again, the services from EXCEPTION are
sufficient to handle this.

What I think is misdesigned is the retry mechanism - to continue after
an exception, an Eiffel routine *must* restart at its beginning and
successfully run through to the end. Retrying is the right answer in
several cases, in particular if hardware is involved, but there are lots
of other applications, and the retry mechanism makes for some ugly and
needlessly complex control flows. (Which is one of the reasons why
exception processing is done only if necessary, which is exactly a
design goal of Eiffel - maybe the unwieldiness of retry is by design?)

Regards,
Joachim
-- 
Please don't send unsolicited ads.






^ permalink raw reply	[flat|nested] 74+ messages in thread

* Re: Building blocks (Was: Design By Contract)
  1997-09-14  0:00                 ` Robert Dewar
@ 1997-09-15  0:00                   ` John G. Volan
  0 siblings, 0 replies; 74+ messages in thread
From: John G. Volan @ 1997-09-15  0:00 UTC (permalink / raw)



Robert Dewar wrote:
> 
> The specific issue in Ada of whether it should be part of the syntax of
> the language to specify the exceptions that can be raised is of course
> one that was extensively discussed, and the quite deliberate decision was
> made that it is unhelpful to require these to be stated in the syntax.
> 
> The reason is that there are too many exceptions (Storage_Error, or the
> various IO errors if any IO is done, or other application defined system
> wide exceptions) which would be named all over the place and create clutter.
> Note that Program_Error would also have to be named almost everwhere because
> of the Access Before Elaboration (ABE) considerations.

There are a couple of strategies that could be applied to this problem:

(1) Take certain common language-defined exceptions as givens (e.g.,
Storage_Error, Program_Error, Constraint_Error).  That is to say, assume
that they are implicitly part of the interface of every
subprogram/method, and don't require the programmer to explicitly list
them.

(2) Make exceptions first-class objects, and take advantage of class
hierarchies to simplify subprogram/method interfaces.  For instance, IO
exceptions might be organized into a hierarchy rooted at some abstract
IO_Exception class.  A method could declare that it can raise any
IO_Exception, without having to explicitly list all the subclasses.

As I understand it, this is essentially the strategy Java uses.  I must
admit that I like being able to treat exceptions as first-class objects
organized in class hierarchies, and I miss that capability in Ada95.  I
wonder why this notion didn't catch on in the Ada95 design ... is it
because first-class exceptions would have introduced a so-called
"distributed overhead" into the language?

-- 
Internet.Usenet.Put_Signature 
  (Name       => "John G. Volan",
   Employer   => "Raytheon/TI Advanced C3I Systems, San Jose, CA",
   Work_Email => "jvolan@ti.com",
   Home_Email => "johnvolan@sprintmail.com",
   Slogan     => "Ada95: World's *FIRST* International-Standard OOPL",
   Disclaimer => "My employer never defined these opinions, so using " & 
                 "them would be totally erroneous...or is that just "  &
                 "nondeterministic behavior now? :-) ");




^ permalink raw reply	[flat|nested] 74+ messages in thread

* Re: Building blocks (Was: Design By Contract)
  1997-09-12  0:00                 ` Robert Dewar
@ 1997-09-16  0:00                   ` Brian Rogoff
  0 siblings, 0 replies; 74+ messages in thread
From: Brian Rogoff @ 1997-09-16  0:00 UTC (permalink / raw)



On 12 Sep 1997, Robert Dewar wrote:
> <... I'm not including anything, it ends here :-) ...> 
> 
> Gosh, another horrible attribution error, that's twice in a week. Sorry
> about that Brian!

Ego te absolvo, Robert! :-) 

I agree that it would be nice if there were a more automatic way to
determine who said what, when. 

-- Brian 





^ permalink raw reply	[flat|nested] 74+ messages in thread

* Re: Building blocks (Was: Design By Contract)
  1997-09-09  0:00 Building blocks (Was: Design By Contract) Marc Wachowitz
  1997-09-15  0:00 ` Joachim Durchholz
@ 1997-09-17  0:00 ` Paul Johnson
  1997-09-18  0:00   ` Stephen Leake
                     ` (2 more replies)
  1 sibling, 3 replies; 74+ messages in thread
From: Paul Johnson @ 1997-09-17  0:00 UTC (permalink / raw)




In article <5v34m5$pl9$1@trumpet.uni-mannheim.de>, Marc Wachowitz
<mw@ipx2.rz.uni-mannheim.de> writes
>paul.johnson@gecm.com (Paul Johnson) wrote:
>> In fact the Eiffel exception mechanism is superior to the Ada one
>> because it is built on a theoretical model of software engineering.
>
>It is only "superior" if you think that Bertrand Meyer's proposed theory
>about exceptions is the only valid one. I don't think it is - and just to
>the contrary, I consider something like Eiffel's class EXCEPTION an ugly
>hack to differentiate between kinds of exceptions.

Which suggests that you are missing the point about DBC.

The precise mechanism by which the client distinguishes between
exceptions is not important (in fact I rather agree with you about
EXCEPTION).

What is important is the fact that ignoring an exception is not an
option.  DBC requires that a class either fulfil its contract or raise
an exception.  The client class which recieves the exception can either
try again a different way or pass the exception on to its client.
Simply hiding the failure under the carpet is not an option.  The
precise nature of the exception is much less important than its
existance.

Ada allows the programmer to quietly ignore an exception and pretend
that a routine succeeded when in fact it failed.  This is wrong.

Paul.
--------------------------------+---------------------------------
Paul Johnson                    | You are lost in a maze of twisty
Email: Paul@treetop.demon.co.uk | little standards, all different.
       paul.johnson@gecm.com    |




^ permalink raw reply	[flat|nested] 74+ messages in thread

* Re: Building blocks (Was: Design By Contract)
  1997-09-18  0:00   ` Stephen Leake
  1997-09-18  0:00     ` W. Wesley Groleau x4923
@ 1997-09-18  0:00     ` Mark L. Fussell
       [not found]       ` <11861963wnr@eiffel.demon.co.uk>
                         ` (2 more replies)
  1 sibling, 3 replies; 74+ messages in thread
From: Mark L. Fussell @ 1997-09-18  0:00 UTC (permalink / raw)




Stephen Leake wrote:
> Paul Johnson wrote:
> > Ada allows the programmer to quietly ignore an exception and pretend
> > that a routine succeeded when in fact it failed.  This is wrong.
> 
> I assume you are talking about:
> begin
>    ... some code
> exception
> when others =>
>    null;
> end;
[SNIP]
> How does Eiffel handle this situation?

A close equivalent in Eiffel is the following example.  This is actually
a variation from the discussion in Section 12.5 of OOSC-2.

is
    -- The Eiffel version of the above
local
    attempts : INTEGER  -- FYI: initializes attempts to 0
do
    if attempts = 0 then
        -- do main stuff
    else
        -- do nothing
    end
rescue
    attempts := attempts + 1
    retry
end

The functionality is identical to the Ada version, so it likewise
"pretends to succeed when in fact it failed".  The important thing to
Bertrand Meyer [from my understanding] is that ONLY the main body can
exit a routine without exception, so we have isolated bad contract
specification and fulfillment (the body) from bad error recovery (the
rescue).  Quoting two relevant paragraphs:

"This example [similar to above] is typical of the use of retry.  The
rescue clause never attempts to reach the original goal using a
substitute implementation; reaching this goal, as expressed by the
postcondition if there is one, is the privelege of the normal body...."
    
"This mechanism strictly adheres to the Disciplined Exception Handling
principle: either a routine succeeds, that is to say its body executes
to the end and satisfies the postcondition, or it fails.  When
interrupted by an exception, you may either report failure or try your
normal body again; in no way can you exit through the rescue clause and
pretend to your caller that you succeeded."
 
Most of the difference between the Eiffel and Ada approach is really
"what it feels like" in the exception handler.  Eiffel's exception
handler give you a chance to retry the main body which can than do what
ever it wants (within its contract), but in so doing returns you to
thinking about how to satisfy the routine call.  The Ada (and many other
languages) approach allows you to try to both recover from the exception
and satisfy the routine call in one place.  This may lead you to forget
to do one or both of these responsibilities.

Certainly Eiffel calls out the 'do nothing' behavior more strongly by
having it be in the main body:
    if attempts = 0 then
        -- do main stuff
    else
        -- do nothing
    end
This looks much stranger and more suspicious than the equivalent:
   begin
      ... some code
   exception
   when others =>
       null;

In the quotes above, the following remark implies more than it means:
"in no way can you exit through the rescue clause and pretend to your
caller that you succeeded".  Since the caller only sees the routine
return, it would not know whether you 'pretended to succeed' via the
rescue/exception clause or through the main body of the routine. 
Pretending to succeed is possible one way or the other.  In either case,
your exiting normally implies you fulfilled your contract
(post-condition) and if Ada had post-conditions then:
   when others => null;
should have to satisfy them or throw a new exception.  To be fair, the
sentence before BM defined 'succeed' more restrictively as the execution
of the body, but that definition is Eiffel specific and the word
'success' has a more general connotation.

--Mark
mark.fussell@chimu.com

  i   ChiMu Corporation      Architectures for Information
 h M   info@chimu.com         Object-Oriented Information Systems
C   u    www.chimu.com         Architecture, Frameworks, and Mentoring




^ permalink raw reply	[flat|nested] 74+ messages in thread

* Re: Building blocks (Was: Design By Contract)
  1997-09-18  0:00   ` Stephen Leake
@ 1997-09-18  0:00     ` W. Wesley Groleau x4923
  1997-09-21  0:00       ` Matthew Heaney
  1997-09-18  0:00     ` Mark L. Fussell
  1 sibling, 1 reply; 74+ messages in thread
From: W. Wesley Groleau x4923 @ 1997-09-18  0:00 UTC (permalink / raw)




Stephen Leake wrote:
> 
> Paul Johnson wrote:
> >
> > Ada allows the programmer to quietly ignore an exception and pretend
> > that a routine succeeded when in fact it failed.  This is wrong.
> 
> I assume you are talking about:
> begin
>    ... some code
> exception
> when others =>
>    null;
> end;
> 
> which ignores exceptions. Usually, this is a bad idea. But sometimes, it
> is essential. Consider the top level loop of a fail-safe system:

Or, perhaps I know that the guy that wrote routine X sometimes 
raises exception Y AFTER X has already done the work I want.
Why shouldn't I ignore exception Y in that case?

> This is a general philosophy of Ada; provide the tools to do various
> jobs. Don't force a programmer to do something because it's "good".

Uh-oh.  That sounds like an argument for a fan of C (Also sounds
like the argument against forcing declaration before reference.)

-- 
----------------------------------------------------------------------
    Wes Groleau, Hughes Defense Communications, Fort Wayne, IN USA
Senior Software Engineer - AFATDS                  Tool-smith Wanna-be
                    wwgrol AT pseserv3.fw.hac.com

Don't send advertisements to this domain unless asked!  All disk space
on fw.hac.com hosts belongs to either Hughes Defense Communications or 
the United States government.  Using email to store YOUR advertising 
on them is trespassing!
----------------------------------------------------------------------




^ permalink raw reply	[flat|nested] 74+ messages in thread

* Re: Building blocks (Was: Design By Contract)
  1997-09-17  0:00 ` Paul Johnson
@ 1997-09-18  0:00   ` Stephen Leake
  1997-09-18  0:00     ` W. Wesley Groleau x4923
  1997-09-18  0:00     ` Mark L. Fussell
  1997-09-18  0:00   ` Jon S Anthony
  1997-09-18  0:00   ` Robert Dewar
  2 siblings, 2 replies; 74+ messages in thread
From: Stephen Leake @ 1997-09-18  0:00 UTC (permalink / raw)



Paul Johnson wrote:
> 
> Ada allows the programmer to quietly ignore an exception and pretend
> that a routine succeeded when in fact it failed.  This is wrong.

I assume you are talking about:
begin
   ... some code
exception 
when others => 
   null;
end;

which ignores exceptions. Usually, this is a bad idea. But sometimes, it 
is essential. Consider the top level loop of a fail-safe system:

loop
   begin
      Initialize;
      loop
         ... do main stuff
      end loop
   exception
   when others =>
      null;
   end;
end loop;

This way, no matter what the "main stuff" does, the outer loop will try
again
if an unhandled exception is raised. Exiting to the "environment" would
be less safe.

How does Eiffel handle this situation?

This is a general philosophy of Ada; provide the tools to do various
jobs. Don't force a programmer to do something because it's "good".
> 
> Paul.
> --------------------------------+---------------------------------
> Paul Johnson                    | You are lost in a maze of twisty
> Email: Paul@treetop.demon.co.uk | little standards, all different.
>        paul.johnson@gecm.com    |

-- 
- Stephe




^ permalink raw reply	[flat|nested] 74+ messages in thread

* Re: Building blocks (Was: Design By Contract)
  1997-09-17  0:00 ` Paul Johnson
  1997-09-18  0:00   ` Stephen Leake
@ 1997-09-18  0:00   ` Jon S Anthony
  1997-09-18  0:00   ` Robert Dewar
  2 siblings, 0 replies; 74+ messages in thread
From: Jon S Anthony @ 1997-09-18  0:00 UTC (permalink / raw)



In article <wihnDCAGPDI0IwlD@treetop.demon.co.uk> Paul Johnson <Paul@treetop.demon.co.uk> writes:

> >It is only "superior" if you think that Bertrand Meyer's proposed theory
> >about exceptions is the only valid one. I don't think it is - and just to
> >the contrary, I consider something like Eiffel's class EXCEPTION an ugly
> >hack to differentiate between kinds of exceptions.
> 
> Which suggests that you are missing the point about DBC.

Or that he sees the point and doesn't think much of it in this
context.


> What is important is the fact that ignoring an exception is not an
> option.  DBC requires that a class either fulfil its contract or raise
> an exception.  The client class which recieves the exception can either
> try again a different way or pass the exception on to its client.
> Simply hiding the failure under the carpet is not an option.  The
> precise nature of the exception is much less important than its
> existance.

OK, but the existence of the exception is not something you can just
completely forget about with no effect.  Either you handle it (ala'
Eiffel) or you don't and then it will eventually get handled (by
someone else) or fall out the bottom and halt the program.


> Ada allows the programmer to quietly ignore an exception and pretend
> that a routine succeeded when in fact it failed.  This is wrong.

How do you figure that?  The only way to "quietly ignore" an exception
is to explicitly handle it _by_ ignoring it:


...
    begin
    ... whatever

    exception
        when others =>
            null;  -- Dirty trick on the client, blow up but
                   -- ignore that fact and pretend it didn't happen.
    end;

I'm not sure how this is really any different than hacking a similar
dirty trick in Eiffel where you simply pretend that things worked OK
(so called, "organized panic" or it's slight variant "resumption").
And you don't need to put in any rescue clause and you just end up
with the default (all the way back to ANY's which does nothing).  This
last is really no different at all from what happens if you have no
user handlers in the Ada case.  I guess the point is simply that
Eiffel does not _ensure_ things will be "done right" any more than Ada
does or for that matter the Java/IDL model.

/Jon
-- 
Jon Anthony
STL, Belmont, MA 02178, 617.484.3383 
"Nightmares - Ha!  The way my life's been going lately,
 Who'd notice?"  -- Londo Mollari






^ permalink raw reply	[flat|nested] 74+ messages in thread

* Re: Building blocks (Was: Design By Contract)
  1997-09-17  0:00 ` Paul Johnson
  1997-09-18  0:00   ` Stephen Leake
  1997-09-18  0:00   ` Jon S Anthony
@ 1997-09-18  0:00   ` Robert Dewar
  2 siblings, 0 replies; 74+ messages in thread
From: Robert Dewar @ 1997-09-18  0:00 UTC (permalink / raw)



iPaul says

<<What is important is the fact that ignoring an exception is not an
option.  DBC requires that a class either fulfil its contract or raise
an exception.  The client class which recieves the exception can either
try again a different way or pass the exception on to its client.
Simply hiding the failure under the carpet is not an option.  The
precise nature of the exception is much less important than its
existance.

Ada allows the programmer to quietly ignore an exception and pretend
that a routine succeeded when in fact it failed.  This is wrong.>>

Paul, can you post a detailed Ada example that shows what you mean
by the last paragraph. Without such an example, it is impossible to
figure out what you think might be "wrong".





^ permalink raw reply	[flat|nested] 74+ messages in thread

* Re: Building blocks (Was: Design By Contract)
       [not found]       ` <11861963wnr@eiffel.demon.co.uk>
@ 1997-09-19  0:00         ` Mark L. Fussell
  0 siblings, 0 replies; 74+ messages in thread
From: Mark L. Fussell @ 1997-09-19  0:00 UTC (permalink / raw)



The following extracts salient thread pieces from Paul Johnson, Stephen
Leake, Roger Browne, and myself.

> > Paul Johnson wrote:
> > > Ada allows the programmer to quietly ignore an exception and pretend
> > > that a routine succeeded when in fact it failed.  This is wrong.

Mark L. Fussell <mark.fussell@chimu.com> writes:
[SNIPPED Eiffel Equivalent of Ada Exception]
> > The functionality [of the Eiffel version] 
> > is identical to the Ada version, so it likewise
> > "pretends to succeed when in fact it failed".  The important thing to
> > Bertrand Meyer [from my understanding] is that ONLY the main body can
> > exit a routine without exception...

Roger Browne wrote:
> ..and therefore it must meet the postcondition of that routine, else
> it triggers a further exception (a "routine failure" exception).
> 
> So, to the extent that the contract can be coded into the postcondition,
> this example does not "pretend to succeed when in fact it failed".

And the Ada and Eiffel examples are equivalent from the caller's point
of view: exactly the same state was reached when the routine returns. 
So we have refuted the concept that Ada routines are "flawed" and can
'pretend to succeed' (via "ignoring" exceptions) where Eiffel routines
can not.  Either both succeeded or both failed.  Either both can pretend
to succeed (by not throwing an exception when the contract is not
fulfilled) or neither can.  

Two differences are (1) Eiffel has postconditions and could better
(automatically) recognize failure which would reduce 'pretending'.  And
(2) the feel of the code is different, possibly leading to focusing more
on fulfilling the contract and recognizing when you can not.  These may
be good (even superior) things in Eiffel but they don't make Ada's
exception mechanism "wrong" or flawed.

--Mark
mark.fussell@chimu.com

  i   ChiMu Corporation      Architectures for Information
 h M   info@chimu.com         Object-Oriented Information Systems
C   u    www.chimu.com         Architecture, Frameworks, and Mentoring




^ permalink raw reply	[flat|nested] 74+ messages in thread

* Re: Building blocks (Was: Design By Contract)
  1997-09-18  0:00     ` Mark L. Fussell
       [not found]       ` <11861963wnr@eiffel.demon.co.uk>
  1997-09-19  0:00       ` Robert A Duff
@ 1997-09-19  0:00       ` Jon S Anthony
  1997-09-23  0:00         ` Mark L. Fussell
  2 siblings, 1 reply; 74+ messages in thread
From: Jon S Anthony @ 1997-09-19  0:00 UTC (permalink / raw)



In article <3421E190.49CC@chimu.com> "Mark L. Fussell" <mark.fussell@chimu.com> writes:

> is
>     -- The Eiffel version of the above
> local
>     attempts : INTEGER  -- FYI: initializes attempts to 0
> do
>     if attempts = 0 then
>         -- do main stuff
>     else
>         -- do nothing
>     end
> rescue
>     attempts := attempts + 1
>     retry
> end

> Most of the difference between the Eiffel and Ada approach is really
> "what it feels like" in the exception handler.

That sounds "right" to me.

>  Eiffel's exception handler give you a chance to retry the main body
> which can than do what ever it wants (within its contract), but in
> so doing returns you to thinking about how to satisfy the routine
> call.  The Ada (and many other languages) approach allows you to try
> to both recover from the exception and satisfy the routine call in
> one place.  This may lead you to forget to do one or both of these
> responsibilities.

Is the Eiffel approach really conceptually different from a recursive
"retry" (where the Eiffel retry is basically a structured goto the
beginning of the current invocation)?  For example,

procedure P (.... Attempts : Natural := 0) is
...
    if Attempts = 0 then
        -- do main stuff
    else
        -- do nothing
    end;
exception
    when others => -- (or more specific exception...)
        P(....Attempts+1)
        ...
end P;


/Jon
-- 
Jon Anthony
STL, Belmont, MA 02178, 617.484.3383 
"Nightmares - Ha!  The way my life's been going lately,
 Who'd notice?"  -- Londo Mollari




^ permalink raw reply	[flat|nested] 74+ messages in thread

* Re: Building blocks (Was: Design By Contract)
  1997-09-18  0:00     ` Mark L. Fussell
       [not found]       ` <11861963wnr@eiffel.demon.co.uk>
@ 1997-09-19  0:00       ` Robert A Duff
  1997-09-20  0:00         ` Joachim Durchholz
  1997-09-19  0:00       ` Jon S Anthony
  2 siblings, 1 reply; 74+ messages in thread
From: Robert A Duff @ 1997-09-19  0:00 UTC (permalink / raw)



In article <3421E190.49CC@chimu.com>,
Mark L. Fussell <mark.fussell@chimu.com> wrote:
>A close equivalent in Eiffel is the following example.  This is actually
>a variation from the discussion in Section 12.5 of OOSC-2.

I read about this in OOSC-1, and I didn't buy it.  It seems to me that
retry has nothing at all to do with whether an operation can "pretend it
succeeded".  The thing that prevents that pretense is having a spec for
what the routine in supposed to do.  In Eiffel, this is represented by
the postcondition and invariant (which may include executable boolean
expressions, plus comments).  In Ada, it's represented mainly by
comments, but perhaps also by constraints, and maybe even
raise_statements in the code.

If Eiffel had Ada-style exception handlers, I don't see how this would
do any damage.  The exception handler would still be required to obey
the postcondition.  Either way, there's always the danger that the
programmer forgot to handle some case correctly.  But that's true even
without exceptions:

    if <some condition> then
        <correct code>
    else
        <wrong code>
    end if;

If <some condition> is usually True, and your test cases fail to
exercise the else branch, then you have a bug that a customer might trip
over.  Likewise, if the main body of a procedure is right, but the
exception handler is wrong, you have a bug.  Either way, the post
condition will catch it at run time.  I don't see how "retry" enhances
the ability of postconditions to find bugs.

Furthermore, retry seems to have all the bad properties of goto.  And
the worst sort of goto -- the kind that jumps backwards in the code,
forming a loop, without actually writing "loop" at the front.

>is
>    -- The Eiffel version of the above
>local
>    attempts : INTEGER  -- FYI: initializes attempts to 0
>do
>    if attempts = 0 then
>        -- do main stuff
>    else
>        -- do nothing
>    end
>rescue
>    attempts := attempts + 1
>    retry
>end

The above code seems obfucatory to me.  If you really want to retry, I
would much rather have an explicit loop:

    loop
        begin
            ... -- do main stuff
            exit;
        exception
            when Some_Error =>
                null;
        end;
    end loop;

Often, you want to do something *different* when the exception occurs
(still, of course, obeying the postcondition).  That's what the above
Eiffel code does, but in a confusing way.  There's no warning at the top
of the code that we might be entering it from the exception handler.  In
that regard, retry is *worse* than a goto -- at least with a backward
goto there's a label there warning you that some other thing might jump
here.  It seems much clearer to say "do THIS in the normal case, but if
you get an exception, do THAT instead".  And of course, THIS and THAT
must obey postconditions.

>"This mechanism strictly adheres to the Disciplined Exception Handling
>principle: either a routine succeeds, that is to say its body executes
>to the end and satisfies the postcondition, or it fails.

This is a bogus definition of "succeed".  The only sensible definition
is "obeys the postcondition".  And that could be achieved just as well
without retry.

>...  When
>interrupted by an exception, you may either report failure or try your
>normal body again; in no way can you exit through the rescue clause and
>pretend to your caller that you succeeded."

But if exception handling were more Ada-like, it would *still* be the
case that "in no way can you ... pretend ...".  You would still be
required to obey the postcondition.

>Most of the difference between the Eiffel and Ada approach is really
>"what it feels like" in the exception handler.  Eiffel's exception
>handler give you a chance to retry the main body which can than do what
>ever it wants (within its contract), but in so doing returns you to
>thinking about how to satisfy the routine call.  The Ada (and many other
>languages) approach allows you to try to both recover from the exception
>and satisfy the routine call in one place.  This may lead you to forget
>to do one or both of these responsibilities.

Just the opposite, IMHO.  With retry, you might forget, when writing the
main body, that you might get there via retry.  With the Ada approach,
you know which situation you're in, and you can write code that
satisfies the postcondition on that basis -- no need for bogus state
variables like the above "attempts", which seem to obfuscate.

>Certainly Eiffel calls out the 'do nothing' behavior more strongly by
>having it be in the main body:
>    if attempts = 0 then
>        -- do main stuff
>    else
>        -- do nothing
>    end
>This looks much stranger and more suspicious than the equivalent:
>   begin
>      ... some code
>   exception
>   when others =>
>       null;

I disagree.  Unless the "when others => null;" is inside a loop (which I
prefer to indicate by saying "loop", rather than the goto-ish backwards
jump of "retry"), it looks mightily suspicious to me.  On the other
hand, in the Eiffel case, if the main body simply said "do main stuff"
(without the if statement), then it seems easier to forget that we might
get here with attempts > 0.

>In the quotes above, the following remark implies more than it means:
>"in no way can you exit through the rescue clause and pretend to your
>caller that you succeeded".  Since the caller only sees the routine
>return, it would not know whether you 'pretended to succeed' via the
>rescue/exception clause or through the main body of the routine. 
>Pretending to succeed is possible one way or the other.

Exactly.

>...In either case,
>your exiting normally implies you fulfilled your contract
>(post-condition) and if Ada had post-conditions then:
>   when others => null;
>should have to satisfy them or throw a new exception.  To be fair, the
>sentence before BM defined 'succeed' more restrictively as the execution
>of the body, but that definition is Eiffel specific and the word
>'success' has a more general connotation.

Agreed.

In summary, I think it's postconditions that help make routines work
properly in all cases (including exceptional cases).  I don't see any
way in which "retry" helps ensure that postconditions are obeyed, and I
think retry simply makes the code more confusing.

- Bob




^ permalink raw reply	[flat|nested] 74+ messages in thread

* Re: Building blocks (Was: Design By Contract)
  1997-09-19  0:00       ` Robert A Duff
@ 1997-09-20  0:00         ` Joachim Durchholz
  1997-09-22  0:00           ` Matthew Heaney
                             ` (3 more replies)
  0 siblings, 4 replies; 74+ messages in thread
From: Joachim Durchholz @ 1997-09-20  0:00 UTC (permalink / raw)



Robert A Duff wrote:
> The exception handler would still be required to obey
> the postcondition.

With the exception that postconditions (even if you writen them down as
raise_statements) aren't handled as well as in Eiffel: They aren't
automatically included in the package documentation, and they aren't
automatically inherited by descendants (if it's a tagged type).

> Either way, there's always the danger that the
> programmer forgot to handle some case correctly.

Agreed.

> Furthermore, retry seems to have all the bad properties of goto.  And
> the worst sort of goto -- the kind that jumps backwards in the code,
> forming a loop, without actually writing "loop" at the front.

I don't particularly like the semantics of retry. I've already seen
Eiffel code that was so obfuscated by squeezing the error handling logic
into a loop that it was actually wrong. And the author was actually one
of the Big Names in the Eiffel community...

Personally, I'd prefer the C++/Java style:
  try
    -- code that may raise an exception
  on <exception identification> do
    -- exception handler
  on <other exception id> do
  ...
  end
(ad-hoc syntax).

I don't like the Ada solution either. It is "structured" in that it will
resume execution at the point where the execution occurred, but that's
*very* wrong. The exception handler can't know at which point in the
code the exception occurred (maybe even in a subroutine!), so it can't
know what to do to fix the problem.
The Eiffel solution is marginally better - it says "if it don't work,
don't try to fix it, try again if there is anything to do about it".
This policy isn't wrong, but it doesn't cover all cases where an
exception might be raised.

[good examples of obfuscated retry statements snipped]

> >"This mechanism strictly adheres to the Disciplined Exception
> Handling
> >principle: either a routine succeeds, that is to say its body
> executes
> >to the end and satisfies the postcondition, or it fails.
> 
> This is a bogus definition of "succeed".  The only sensible definition
> is "obeys the postcondition".  And that could be achieved just as well
> without retry.

Yup.
Though Ada has no formal connection to postconditions, so it doesn't
offer us guidelines what to do about an exception.

What's disciplined about Eiffel exceptions is not the retry instruction,
which is somewhat secondary. The discipline of exception handling in
Eiffel has other sources:
- A precise definition of what an exception indicates (namely a routine
that fails to fulfill its postcondition - other languages, lacking the
notion of postcondition, can't even start to compete)
- A strict guideline when to raise an exception explicitly: if something
uncontrollable happens that makes fulfilling a postcondition
imnpossible. Such uncontrollable events are: actions by concurrent
threads, bugs, unhandled exceptions in called routines, and algorithms
where controlling the problems is nearly as expensive as just trying
(like in matrix inversion, where determining wether a matrix is
invertible takes nearly as long as just starting the inversion and
aborting if a division by zero occurs).
- A strong guideline *not* to use exceptions as interprocedural goto.
(I'm pretty sure that this is frowned upon by all serious Ada shops, but
it's still a difference if such a guideline is expressed in all
textbooks from the beginning of if you have to install such a policy. I
call such conventions "language culture" - it's not part of the formal
specification, but important enough to strongly influence the average
quality of programs written in a language.)

> In summary, I think it's postconditions that help make routines work
> properly in all cases (including exceptional cases).  I don't see any
> way in which "retry" helps ensure that postconditions are obeyed, and
> I
> think retry simply makes the code more confusing.

Right.

Regards,
Joachim
-- 
Please don't send unsolicited ads.






^ permalink raw reply	[flat|nested] 74+ messages in thread

* Re: Building blocks (Was: Design By Contract)
  1997-09-18  0:00     ` W. Wesley Groleau x4923
@ 1997-09-21  0:00       ` Matthew Heaney
  0 siblings, 0 replies; 74+ messages in thread
From: Matthew Heaney @ 1997-09-21  0:00 UTC (permalink / raw)



In article <3421A76F.4709@pseserv3.fw.hac.com>, "W. Wesley Groleau x4923"
<wwgrol@pseserv3.fw.hac.com> wrote:


>Or, perhaps I know that the guy that wrote routine X sometimes 
>raises exception Y AFTER X has already done the work I want.
>Why shouldn't I ignore exception Y in that case?

This is a misuse of the exception mechanism.  Either the subprogram does
the work, satisfying the postcondition, or raises an exception, because it
cannot satisfy its postcondition.  Don't use exceptions as a way of passing
back status in the normal case, use them strictly to indicate failure to
satisfy postconditions.  (And also to indicate failure by the client to
satisfy preconditions.)

--------------------------------------------------------------------
Matthew Heaney
Software Development Consultant
<mailto:matthew_heaney@acm.org>
(818) 985-1271




^ permalink raw reply	[flat|nested] 74+ messages in thread

* Re: Building blocks (Was: Design By Contract)
  1997-09-20  0:00         ` Joachim Durchholz
@ 1997-09-22  0:00           ` Matthew Heaney
  1997-09-23  0:00             ` Veli-Pekka Nousiainen
  1997-09-23  0:00             ` Joachim Durchholz
  1997-09-23  0:00           ` Jon S Anthony
                             ` (2 subsequent siblings)
  3 siblings, 2 replies; 74+ messages in thread
From: Matthew Heaney @ 1997-09-22  0:00 UTC (permalink / raw)



In article <3423BE13.9C3852A4@munich.netsurf.de>, Joachim Durchholz
<joachim.durchholz@munich.netsurf.de> wrote:


>I don't like the Ada solution either. It is "structured" in that it will
>resume execution at the point where the execution occurred, but that's
>*very* wrong. The exception handler can't know at which point in the
>code the exception occurred (maybe even in a subroutine!), so it can't
>know what to do to fix the problem.

I don't understand what you mean by "resume execution at the point where
the execution [exception?] occurred," because Ada does NOT resume execution
at the point of the exception.  Rather, normal execution is abandoned, and
control passes to the exception handler.

You are correct in stating that the exception handler can't know at which
point the exception occured, but only if there is a "large" amount of
program text covered by a handler, and there is more the one place where
the exception can occur.  The solution in this case is to localize handling
of the exception, so that it isn't ambiguous:

begin
   X := new T;
exception
   when Storage_Error =>
       raise Stack_Full;
end;


>Though Ada has no formal connection to postconditions, so it doesn't
>offer us guidelines what to do about an exception.

While it's true that Ada syntax does not include a mechanism of specifying
which exceptions can be raised by a subprogram, I wouldn't say that there
are "no guidelines" for what to do about an exception.  You simply state -
in the form of a comment - which exceptions can be raised by a subprogram,
and handle them as appropriate.  

>What's disciplined about Eiffel exceptions is not the retry instruction,
>which is somewhat secondary. The discipline of exception handling in
>Eiffel has other sources:
>- A precise definition of what an exception indicates (namely a routine
>that fails to fulfill its postcondition - other languages, lacking the
>notion of postcondition, can't even start to compete)

This statement confuses syntax with semantics.  By a very deliberate choice
during language design, 
there is not always a way in Ada to state syntactically what the
postcondition of a subprogram is (and never any way to state what
exceptions are propagated by a subprogram).   However, in Ada, you do state
what the postcondition is, in the form of a comment.  It is clearly not the
case that Ada - or any other language - "lacks a notion of postcondition." 

So yes, in Ada, you really do raise an exception when you are unable to
satisfy a postcondition, it's just that the postcondition and possible
exceptions raised cannot be stated as part of Ada syntax; they must be
stated as a comment.

Of course, there's nothing to prevent a programmer from failing to fulfill
his postcondition, or from raising exceptions he hasn't advertised, just as
there is no way to prevent a programmer from returning the value of the
cosine from a function called Sin.  But this is a programmer problem, not
an Ada problem.

>- A strict guideline when to raise an exception explicitly: if something
>uncontrollable happens that makes fulfilling a postcondition
>imnpossible. Such uncontrollable events are: actions by concurrent
>threads, bugs, unhandled exceptions in called routines, and algorithms
>where controlling the problems is nearly as expensive as just trying
>(like in matrix inversion, where determining wether a matrix is
>invertible takes nearly as long as just starting the inversion and
>aborting if a division by zero occurs).

This is the same guideline one uses in Ada.

--------------------------------------------------------------------
Matthew Heaney
Software Development Consultant
<mailto:matthew_heaney@acm.org>
(818) 985-1271




^ permalink raw reply	[flat|nested] 74+ messages in thread

* Re: Building blocks (Was: Design By Contract)
  1997-09-22  0:00           ` Matthew Heaney
@ 1997-09-23  0:00             ` Veli-Pekka Nousiainen
  1997-10-03  0:00               ` Robert I. Eachus
  1997-09-23  0:00             ` Joachim Durchholz
  1 sibling, 1 reply; 74+ messages in thread
From: Veli-Pekka Nousiainen @ 1997-09-23  0:00 UTC (permalink / raw)





Matthew Heaney <mheaney@ni.net> wrote in article
<mheaney-ya023680002209971930310001@news.ni.net>...
> In article <3423BE13.9C3852A4@munich.netsurf.de>, Joachim Durchholz
> <joachim.durchholz@munich.netsurf.de> wrote:
> 
<SNIP> 
> 
> >What's disciplined about Eiffel exceptions is not the retry instruction,
> >which is somewhat secondary. The discipline of exception handling in
> >Eiffel has other sources:
> >- A precise definition of what an exception indicates (namely a routine
> >that fails to fulfill its postcondition - other languages, lacking the
> >notion of postcondition, can't even start to compete)
> 
> This statement confuses syntax with semantics.  By a very deliberate
choice
> during language design, 
> there is not always a way in Ada to state syntactically what the
> postcondition of a subprogram is (and never any way to state what
> exceptions are propagated by a subprogram).   However, in Ada, you do
state
> what the postcondition is, in the form of a comment.  It is clearly not
the
> case that Ada - or any other language - "lacks a notion of
postcondition." 

It is clear to me that postconditioning is missing in all other languages
exept Eiffel (Sather???). If all you need is comments, then my old
hex-assembler for an 8-bit processor is all O-O with DbC, I just comment
:-)
> 
> So yes, in Ada, you really do raise an exception when you are unable to
> satisfy a postcondition, it's just that the postcondition and possible
> exceptions raised cannot be stated as part of Ada syntax; they must be
> stated as a comment.
> 
<SNIP> 
> 
IMO
-- 
-------------------------------------------------------------------------
Veli-Pekka Nousiainen
Sokinsuontie 3 A 1, FIN-02760 Espoo, Finland
TEL +358-9-859 2025 ; GSM 0400-5940 824
e-mail: vp.nousiainen@remove_this_eiffel.fi
-------------------------------------------------------------------------




^ permalink raw reply	[flat|nested] 74+ messages in thread

* Re: Building blocks (Was: Design By Contract)
  1997-09-19  0:00       ` Jon S Anthony
@ 1997-09-23  0:00         ` Mark L. Fussell
  0 siblings, 0 replies; 74+ messages in thread
From: Mark L. Fussell @ 1997-09-23  0:00 UTC (permalink / raw)
  To: Jon S Anthony


Jon S Anthony wrote:
...
> Is the Eiffel approach really conceptually different from a recursive
> "retry" (where the Eiffel retry is basically a structured goto the
> beginning of the current invocation)?  For example,
> 
> procedure P (.... Attempts : Natural := 0) is
> ...
>     if Attempts = 0 then
>         -- do main stuff
>     else
>         -- do nothing
>     end;
> exception
>     when others => -- (or more specific exception...)
>         P(....Attempts+1)
>         ...
> end P;

I agree that this is pretty similar to my/OOSC-2s example.  The obvious
difference is you have publicly exposed the 'attempts' variable which is
an implementation detail, but of course this could be hidden through a
second, private procedure/feature that is delegated to.  And the general
case could have 0..N state variables passed back in.
   The more important [IMO] difference is the 'feel' again.  The above
code shows the flexibility in exception handling that Eiffel consciously
chose to disallow: having anything other than the current invocation's
main body 'continue' from an exception.  So the above code functions
almost identically to the Eiffel code but it implies the possibility of
a different solution (different responsibility) which Eiffel never
would.  Whether you view this as a guiding hand or hand-cuffs is
probably very subjective.  I doubt there is any empirical evidence that
this particular Eiffel restriction produces better software[1], but it
obviously does fit in well with Eiffel as a whole as it came from the
same mind.

--Mark
mark.fussell@chimu.com

[1] In my previous post I guessed at what it might help with: returning
you to thinking about how to satisfy the routine call after you recover
from the exception itself.  You certainly have to jump through an extra
hoop to carelessly ignore an exception: you don't have the
Java/C++/standard short-circuit construct:
    try {
        ...
    } catch (Exception e) {};
But as multiple people have noted, there is a time for everything, and
the above construct can be useful, for example, if you have a valid
state before the 'try' and nothing within the 'try' will invalidate it
(i.e. it will only move to another valid state or not at all).
   So we always return to the same meta-question: when should
programmers be free but disciplined and when should they be confined? 
What tradeoffs are appropriate in each context?  Hmmm... should be a
'Pattern' for this somewhere out there.

  i   ChiMu Corporation      Architectures for Information
 h M   info@chimu.com         Object-Oriented Information Systems
C   u    www.chimu.com         Architecture, Frameworks, and Mentoring




^ permalink raw reply	[flat|nested] 74+ messages in thread

* Re: Building blocks (Was: Design By Contract)
  1997-09-20  0:00         ` Joachim Durchholz
  1997-09-22  0:00           ` Matthew Heaney
@ 1997-09-23  0:00           ` Jon S Anthony
  1997-09-24  0:00           ` Alan E & Carmel J Brain
  1997-09-24  0:00           ` Richard A. O'Keefe
  3 siblings, 0 replies; 74+ messages in thread
From: Jon S Anthony @ 1997-09-23  0:00 UTC (permalink / raw)



In article <3423BE13.9C3852A4@munich.netsurf.de> Joachim Durchholz <joachim.durchholz@munich.netsurf.de> writes:

> I don't like the Ada solution either. It is "structured" in that it will
> resume execution at the point where the execution occurred, but that's
> *very* wrong. The exception handler can't know at which point in the
> code the exception occurred (maybe even in a subroutine!), so it can't
> know what to do to fix the problem.

??? What do you mean here?  Surely it is clear enough that Ada does
not support resumption semantics in exception handling.  So, you must
have something in mind here, but I can't figure out what it is...

/Jon
-- 
Jon Anthony
STL, Belmont, MA 02178, 617.484.3383 
"Nightmares - Ha!  The way my life's been going lately,
 Who'd notice?"  -- Londo Mollari




^ permalink raw reply	[flat|nested] 74+ messages in thread

* Re: Building blocks (Was: Design By Contract)
  1997-09-22  0:00           ` Matthew Heaney
  1997-09-23  0:00             ` Veli-Pekka Nousiainen
@ 1997-09-23  0:00             ` Joachim Durchholz
  1 sibling, 0 replies; 74+ messages in thread
From: Joachim Durchholz @ 1997-09-23  0:00 UTC (permalink / raw)



Matthew Heaney wrote:
> 
> In article <3423BE13.9C3852A4@munich.netsurf.de>, Joachim Durchholz
> <joachim.durchholz@munich.netsurf.de> wrote:
> 
> I don't understand what you mean by "resume execution at the point
> where
> the execution [exception?] occurred," because Ada does NOT resume
                 ^ yes that's what I meant
> execution
> at the point of the exception.  Rather, normal execution is abandoned,
> and
> control passes to the exception handler.

Sorry, I take that point back. There was a mental mix-up involved.

> You are correct in stating that the exception handler can't know at
> which
> point the exception occured, but only if there is a "large" amount of
> program text covered by a handler, and there is more the one place
> where
> the exception can occur.  The solution in this case is to localize
> handling
> of the exception, so that it isn't ambiguous:

Agreed.

> >Though Ada has no formal connection to postconditions, so it doesn't
> >offer us guidelines what to do about an exception.
> 
> While it's true that Ada syntax does not include a mechanism of
> specifying
> which exceptions can be raised by a subprogram, I wouldn't say that
> there
> are "no guidelines" for what to do about an exception.  You simply
> state -
> in the form of a comment - which exceptions can be raised by a
> subprogram,
> and handle them as appropriate.

Hmm... that's exactly what I mean. I'm sure your shop has conventions on
what form these comments should take, but other shops might have
different forms. So you have to train every new programmer to write the
"right" comments. So you can't sell a database that collects the
exception information. There are *many* advantages to have a fixed
syntactical place to place the postconditions.

> >What's disciplined about Eiffel exceptions is not the retry
> instruction,
> >which is somewhat secondary. The discipline of exception handling in
> >Eiffel has other sources:
> >- A precise definition of what an exception indicates (namely a
> routine
> >that fails to fulfill its postcondition - other languages, lacking
> the
> >notion of postcondition, can't even start to compete)
> 
> This statement confuses syntax with semantics.

Huh?
A postcondition has a very real semantics in Eiffel. The syntax is just
that - syntax that's necessary to indicate the compiler what these
boolean expressions are about.

[Stuff on not formalizing the set of possible exceptions for Ada
snipped.]

> It is clearly
> not the
> case that Ada - or any other language - "lacks a notion of
> postcondition."

Oh yes it does. In the same way as assembler lacks the notion of
parameter type - yes you can emulate it by heavy commenting and adhering
to informal guidelines, but then the notion is not implemented in the
language, it is implemented in the programming organization around that
language.

> Of course, there's nothing to prevent a programmer from failing to
> fulfill
> his postcondition, or from raising exceptions he hasn't advertised,
> just as
> there is no way to prevent a programmer from returning the value of
> the
> cosine from a function called Sin.  But this is a programmer problem,
> not
> an Ada problem.

Yup. And nothing will prevent an Eiffel programmer from doing the same.

However, such errors are more obtrusive in an Eiffel class. Eiffel
routines are typically very short, so a mismatch between a routine body
and its postcondition is often obvious at the first casual glance. (Of
course most programmers will see that even before writing the bug, so
not many bugs of this type manifest themselves to begin with.)

> >- A strict guideline when to raise an exception explicitly: if
> something
> >uncontrollable happens that makes fulfilling a postcondition
> >imnpossible. Such uncontrollable events are: actions by concurrent
> >threads, bugs, unhandled exceptions in called routines, and
> algorithms
> >where controlling the problems is nearly as expensive as just trying
> >(like in matrix inversion, where determining wether a matrix is
> >invertible takes nearly as long as just starting the inversion and
> >aborting if a division by zero occurs).
> 
> This is the same guideline one uses in Ada.

It's the guideline that *should* be used in Ada. But I'd bet it isn't
always followed - with pressing deadlines and less-than-perfect
programmers in the shop, you can't be sure that your company's
guidelines will always be followed to the letter or (more importantly)
in spirit.
In Eiffel, letter and spirit are the same, and the policy is already
enforced by the compiler.

Regards,
Joachim
-- 
Please don't send unsolicited ads.





^ permalink raw reply	[flat|nested] 74+ messages in thread

* Re: Building blocks (Was: Design By Contract)
  1997-09-20  0:00         ` Joachim Durchholz
  1997-09-22  0:00           ` Matthew Heaney
  1997-09-23  0:00           ` Jon S Anthony
@ 1997-09-24  0:00           ` Alan E & Carmel J Brain
  1997-09-25  0:00             ` Anonymous
  1997-09-24  0:00           ` Richard A. O'Keefe
  3 siblings, 1 reply; 74+ messages in thread
From: Alan E & Carmel J Brain @ 1997-09-24  0:00 UTC (permalink / raw)



Joachim Durchholz wrote:

> Personally, I'd prefer the C++/Java style:
>   try
>     -- code that may raise an exception
>   on <exception identification> do
>     -- exception handler
>   on <other exception id> do
>   ...
>   end
> (ad-hoc syntax).
> 
> I don't like the Ada solution either. It is "structured" in that it will
> resume execution at the point where the execution occurred, but that's
> *very* wrong. The exception handler can't know at which point in the
> code the exception occurred (maybe even in a subroutine!), so it can't
> know what to do to fix the problem.

Eh???

The syntax for Ada looks like:

procedure WhatEver is

begin
  -- statements
  -- more statements
  -- end of normal execution
exception
  when SOME_ERROR => do something;
  when SOME_OTHER_ERROR => do something else;
  when others => raise; -- just propogate to caller
end WhatEver;

There is no resumption! Any exception raised between the "begin" and
"exception" immediately causes abandonment of normal execution, like a
GOTO, to the exception block.

If you want to resume, or retry, or whatever, you need to confine the
exception to it's own block. A typical example looks something like:

(Declarations, Constants omitted for simplicity)

UnTransmitted := true;
ReTryCounter := 0;

while UnTransmitted loop
    
  if ReTryCounter > MaxRetries then
     raise LineContinuouslyBusy; end if; -- Line Too busy
                                         -- Report this upwards
  Transmission_Attempt_Block :
  begin

    Ethernet.TryToTransmit;
    UnTransmitted := false; -- Successful Transmission

  exception
    when Ethernet.LINE_BUSY =>
	ReTryCounter := ReTryCounter+1; -- Try again
                                        -- Note that this 'handles'
                                        -- the exception
    when Ethernet.NACK =>
        Untransmitted := false;         -- Ignore Negative Ack.
                                        -- Again, exception handled.
    when others => raise;
	-- something unexpected and Nasty, Propagate it out!
        
  end Transmission_Attempt_Block;

end loop;

Note that the LINE_BUSY exception, declared in package ETHERNET is
normal, expected, and handlable locally, at least up to a point. Any
other exceptions coming from a call to Ethernet.TryToTransmit will be
propagated upwards and outwards: there is not enough data locally to
determine what to do here. Similarly, if the line is continuously busy,
an exception stating this is propagated upwards. In the case of a NACK
exception, cross fingers, hope it's OK, etc. Normally a VERY bad idea,
but on hardware which gives 30% or more false positives, it may be the
only way to go.

Personally, I like the flexibility.
 
-- 
aebrain@dynamite.com.au     <> <>    How doth the little Crocodile
| Alan & Carmel Brain|      xxxxx       Improve his shining tail?
| Canberra Australia |  xxxxxHxHxxxxxx _MMMMMMMMM_MMMMMMMMM
 abrain@cs.adfa.oz.au  o OO*O^^^^O*OO o oo     oo oo     oo  
                    By pulling MAERKLIN Wagons, in 1/220 Scale






^ permalink raw reply	[flat|nested] 74+ messages in thread

* Re: Building blocks (Was: Design By Contract)
  1997-09-20  0:00         ` Joachim Durchholz
                             ` (2 preceding siblings ...)
  1997-09-24  0:00           ` Alan E & Carmel J Brain
@ 1997-09-24  0:00           ` Richard A. O'Keefe
  3 siblings, 0 replies; 74+ messages in thread
From: Richard A. O'Keefe @ 1997-09-24  0:00 UTC (permalink / raw)



Joachim Durchholz <joachim.durchholz@munich.netsurf.de> writes:
>I don't like the Ada solution either. It is "structured" in that it will
>resume execution at the point where the execution occurred, but that's
>*very* wrong. The exception handler can't know at which point in the
>code the exception occurred (maybe even in a subroutine!), so it can't
>know what to do to fix the problem.

Are we talking about the same language?
Ada exceptions are 'termination' exceptions.
PL/I has exception resumption.
Common Lisp has exception resumption.
Ada does not.
One thing an Ada exception handler _can't_ do is
"resume execution at the point where the exception" was raised.

-- 
Unsolicited commercial E-mail to this account is prohibited; see section 76E
of the Commonwealth Crimes Act 1914 as amended by the Crimes Legislation
Amendment Act No 108 of 1989.  Maximum penalty:  10 years in gaol.
Richard A. O'Keefe; http://www.cs.rmit.edu.au/%7Eok; RMIT Comp.Sci.




^ permalink raw reply	[flat|nested] 74+ messages in thread

* Re: Building blocks (Was: Design By Contract)
  1997-09-24  0:00           ` Alan E & Carmel J Brain
@ 1997-09-25  0:00             ` Anonymous
  1997-09-30  0:00               ` Alan E & Carmel J Brain
  0 siblings, 1 reply; 74+ messages in thread
From: Anonymous @ 1997-09-25  0:00 UTC (permalink / raw)



<5v34m5$pl9$1@trumpet.uni-mannheim.de>
<wihnDCAGPDI0IwlD@treetop.demon.co.uk> <34215E3D.77AE@gsfc.nasa.gov>
<3421E190.49CC@chimu.com> <EGrz21.GoG@world.std.com>
<3423BE13.9C3852A4@munich.netsurf.de>

On Wed, 24 Sep 1997 23:55:02 -0700, Alan E & Carmel J Brain
<aebrain@dynamite.com.au> wrote:
>[...]
> If you want to resume, or retry, or whatever, you need to confine the
> exception to it's own block. A typical example looks something like:
> 
> (Declarations, Constants omitted for simplicity)
> 
> UnTransmitted := true;
> ReTryCounter := 0;
> 
> while UnTransmitted loop
>     
>   if ReTryCounter > MaxRetries then
>      raise LineContinuouslyBusy; end if; -- Line Too busy
>                                          -- Report this upwards
>   Transmission_Attempt_Block :
>   begin
> 
>     Ethernet.TryToTransmit;
>     UnTransmitted := false; -- Successful Transmission
> 
>   exception
>     when Ethernet.LINE_BUSY =>
> 	ReTryCounter := ReTryCounter+1; -- Try again
>                                         -- Note that this 'handles'
>                                         -- the exception
>     when Ethernet.NACK =>
>         Untransmitted := false;         -- Ignore Negative Ack.
>                                         -- Again, exception handled.
>     when others => raise;
> 	-- something unexpected and Nasty, Propagate it out!
>         
>   end Transmission_Attempt_Block;
> 
> end loop;
> 

This doesn't seem typical to me. It differs from typical in

1. Using mixed-case identifiers instead of underline-separated
identifiers (ReTryCounter instead of Re_Try_Counter).

2. Using while instead of loop/exit (ref. Ichbiah, Barnes, & Firth, "Ada
Launch," 1980 Dec 10, videotape, on why while was included in the
language).

3. The design of Ethernet is faulty, since it uses exceptions for
non-exceptional circumstances (line busy, NACK received).

4. Unusual formatting of the if.

If we have to use Ethernet as is, I'd say the following is more typical

Retry_Counter := 0;

Send : loop
   if Retry_Counter > Max_Retries then
      raise Line_Continuously_Busy;
   end if; -- Line too busy; report this upwards

   Try_One : begin
      Ethernet.Try_To_Transmit;

      exit Send; -- Successful transmission
   exception -- Try_One
   when Ethernet.Line_Busy =>
      Retry_Counter := Retry_Counter + 1; -- Try again
   when Ethernet.Nack =>
      exit Send; -- Accept NACK as success
   end Try_One;
end loop Send;

Jeff Carter  PGP:1024/440FBE21
My real e-mail address: ( carter @ innocon . com )
"You brightly-colored, mealy-templed, cranberry-smelling, electric
donkey-bottom biters."
Monty Python & the Holy Grail

Posted with Spam Hater - see
http://www.compulink.co.uk/~net-services/spam/




^ permalink raw reply	[flat|nested] 74+ messages in thread

* Re: Building blocks (Was: Design By Contract)
  1997-09-25  0:00             ` Anonymous
@ 1997-09-30  0:00               ` Alan E & Carmel J Brain
  1997-09-30  0:00                 ` Matthew Heaney
  1997-10-01  0:00                 ` Anonymous
  0 siblings, 2 replies; 74+ messages in thread
From: Alan E & Carmel J Brain @ 1997-09-30  0:00 UTC (permalink / raw)



Anonymous wrote:

> > If you want to resume, or retry, or whatever, you need to confine the
> > exception to it's own block. A typical example looks something like:
> >
> > (Declarations, Constants omitted for simplicity)
> >
> > UnTransmitted := true;
> > ReTryCounter := 0;
> >
> > while UnTransmitted loop
> >
> >   if ReTryCounter > MaxRetries then
> >      raise LineContinuouslyBusy; end if; -- Line Too busy
> >                                          -- Report this upwards
> >   Transmission_Attempt_Block :
> >   begin
> >
> >     Ethernet.TryToTransmit;
> >     UnTransmitted := false; -- Successful Transmission
> >
> >   exception
> >     when Ethernet.LINE_BUSY =>
> >       ReTryCounter := ReTryCounter+1; -- Try again
> >                                         -- Note that this 'handles'
> >                                         -- the exception
> >     when Ethernet.NACK =>
> >         Untransmitted := false;         -- Ignore Negative Ack.
> >                                         -- Again, exception handled.
> >     when others => raise;
> >       -- something unexpected and Nasty, Propagate it out!
> >
> >   end Transmission_Attempt_Block;
> >
> > end loop;
> >
> 
> This doesn't seem typical to me. It differs from typical in
> 
> 1. Using mixed-case identifiers instead of underline-separated
> identifiers (ReTryCounter instead of Re_Try_Counter).

Good point, thanks for the correction. Ain't walk-through's wonderful?
 
> 2. Using while instead of loop/exit (ref. Ichbiah, Barnes, & Firth, "Ada
> Launch," 1980 Dec 10, videotape, on why while was included in the
> language).

I'd defend this one on style grounds, and believe the matter is
religious. I have no access to this video. Any other sources? BTW
perfectly willing to believe I'm wrong, I just want to know why...

> 3. The design of Ethernet is faulty, since it uses exceptions for
> non-exceptional circumstances (line busy, NACK received).

Depends on the domain. Either of these may be exceptional (e.g. in a
1-way broadcast architecture) or normal (e.g. many nodes, all of whom
may talk).
 
> 4. Unusual formatting of the if.

Style again. If expressible more clearly on one or two lines, use that,
otherwise a more normal format would be

  if CONDITIONAL then
    STATEMENT;
    STATEMENT;
  end if;

or even

  if CONDITIONAL
  then
    STATEMENT;
  end if;
 
> If we have to use Ethernet as is, I'd say the following is more typical
> 
> Retry_Counter := 0;
> 
> Send : loop
>    if Retry_Counter > Max_Retries then
>       raise Line_Continuously_Busy;
>    end if; -- Line too busy; report this upwards
> 
>    Try_One : begin
>       Ethernet.Try_To_Transmit;
> 
>       exit Send; -- Successful transmission

I'd insert a blank line here for readability
and a few others, as below:

>    exception -- Try_One

>    when Ethernet.Line_Busy =>
>       Retry_Counter := Retry_Counter + 1; -- Try again

>    when Ethernet.Nack =>
>       exit Send; -- Accept NACK as success

>    end Try_One;

> end loop Send;


Makes sense to me. OTOH there is a school of thought that eschews
multiple exits. But that's another story. The point is, is that both
versions show in a minimum number of lines the various options one has
in Ada ( -83 at least, there are more in -95), which was the basic idea.

> "You brightly-colored, mealy-templed, cranberry-smelling, electric
> donkey-bottom biters."

Was this meant personally? (<g> added for the hard-of-thinking) If so, I
take exception! (That's supposed to be a pun.... never mind...)
-- 
aebrain@dynamite.com.au     <> <>    How doth the little Crocodile
| Alan & Carmel Brain|      xxxxx       Improve his shining tail?
| Canberra Australia |  xxxxxHxHxxxxxx _MMMMMMMMM_MMMMMMMMM
 abrain@cs.adfa.oz.au  o OO*O^^^^O*OO o oo     oo oo     oo  
                    By pulling MAERKLIN Wagons, in 1/220 Scale





^ permalink raw reply	[flat|nested] 74+ messages in thread

* Re: Building blocks (Was: Design By Contract)
  1997-09-30  0:00               ` Alan E & Carmel J Brain
@ 1997-09-30  0:00                 ` Matthew Heaney
  1997-09-30  0:00                   ` W. Wesley Groleau x4923
  1997-09-30  0:00                   ` Neil Wilson
  1997-10-01  0:00                 ` Anonymous
  1 sibling, 2 replies; 74+ messages in thread
From: Matthew Heaney @ 1997-09-30  0:00 UTC (permalink / raw)



In article <34316EC3.5B62@dynamite.com.au>, aebrain@dynamite.com.au wrote:


>> 2. Using while instead of loop/exit (ref. Ichbiah, Barnes, & Firth, "Ada
>> Launch," 1980 Dec 10, videotape, on why while was included in the
>> language).
>
>I'd defend this one on style grounds, and believe the matter is
>religious. I have no access to this video. Any other sources? BTW
>perfectly willing to believe I'm wrong, I just want to know why...

Yes, it's quite wrong to use a flag to terminate a while loop, instead of
just using exit with a loop.  The idiom is, use an exit when the
termination depends on what you read, eg

loop

   <read some data>

   exit when <the data has some special value>

   <process the data>

end loop;

The classic example is, read some integers until the user types in the value 0:

loop

   Read (N);
   exit when N = 0;

   <process N>

end loop;

Scannars are written this way: you leave the current state when you've read
something outside what you're scanning right now:

Scan_Integer:
loop

   Read (C);
   exit when C not in '0' .. '9';
 
   <process this digit>

end loop Scan_Integer;


No, this is not a moral issue.  It is a simple fact about what
problem-solving strategies are best for human programmers.  That the exit
technique is a better "cognitive fit" was demonstrated empirically in

Cognitive Strategies and Looping Constructs: An Empirical Study
Elliot Soloway et al
CACM Nov 83 Vol 26 Number 11, p. 853-860.

From the abstract:
...Our results indicate that subjects overwhelmingly prefered a
READ/PROCESS strategy over a PROCESS/READ strategy.  When writing a simple
looping program, those using the loop .. leave .. again construct were more
often correct than those using  the standard Pascal loop constructs.

Here's another excerpt from an older textbook:

<Greater flexibility in choosing program structures is possible if one can
"exit" from a program segment "prematurely" -- that is, if one can
terminate the execution of a certain segment of program before its normal
completion.  In the case of a DO group this means being able to terminate
one particular iteration of the body [mjh: something you can't do in Ada,
but can in C using "continue"], or terminate the execution of the entire DO
group [mjh: "exit" in Ada or "break" in C].  In PL/I this type of exit must
be accomplished by a "conditional branch.">

-- from An Introduction to Programming, Richard Conway and David Gries

In a recent thread on this list, we debated why Ada requires you for
declare something before its use.  The design philosophy of Ada - as
explained in the video and to me privately by Jean Ichbiah - is that the
programmer's understanding of something should only depend on what has come
before.  He shouldn't have to read ahead.  What he needs to know to
apprehend the program text only depends on the text he's already read.

Your example is a classic example of how NOT to write loop, by setting a
flag to false to force a while loop to terminate. The problem is that the
reader of your code has to read THE ENTIRE BODY OF THE LOOP, after you've
set the flag to false, to determine whether you set the flag because you
want to terminate the loop right now, and whether there's more work to be
done, prior to the actual end of the loop.  The flag is AMBIGUOUS.

If you reach a point where you need to terminate the loop, then terminate
the loop, right now.  Don't set a flag, execute the rest of the body, test
the flag, to terminate the loop.  Just terminate the loop.

If you want to go from point A to point B, then go directly from point A to
point B.  Why go from A to C to D then to B?  Especially as that may
confuse the person trying to follow you.

You can make the argument "this is just my style," but the whole underlying
philosophy of Ada is that program text gets read by other human
programmers, not just by the human who wrote it originally, and we should
do as much to facilitate their understanding as possible.  This means
presenting information in a manner best suited for the human reader, not
just the compiler.

So your "style" may be the source of obfuscation and ambiguity that CONFUSE
human readers of your programs.  You don't live on an island.  We all need
to always think about the programmer playing detective who's trying to
figure out what we've written.  Always ask yourself as you're writing code,
What can I do to make it easy for someone reading this?  This is especially
true when you have a choice about how to do something, and either way will
work; it's called the Principle of Least Astonishment.

When you reach a loop termination point, tell the human programmer reading
your code, directly and unambiguously, that you want to terminate the loop,
by using an exit.

A loop exit is a big huge sign that tells the person reading your code that
THE LOOP IS TERMINATING NOW.  Nothing unambiguous about that.  No more text
to try to figure out.  All very simple, which is precisely what we want.

One more point.  Among the colorful landscape of programming languages, Ada
is a very conservative language.  If a construct were so pernicious that it
made writing correct programs difficult, or made the apprehension of
program text difficult, then it wouldn't be in the language, now would it? 
A bunch of guys with PhDs in computer science from all over the planet
voted unaminously to make 
Ada an international programming language standard.  And _they_ all decided
that exiting from a loop was OK.

There's nothing extra to you need to do to make Ada programming safe,
because it comes that way right out of the box.

--------------------------------------------------------------------
Matthew Heaney
Software Development Consultant
<mailto:matthew_heaney@acm.org>
(818) 985-1271




^ permalink raw reply	[flat|nested] 74+ messages in thread

* Re: Building blocks (Was: Design By Contract)
  1997-09-30  0:00                 ` Matthew Heaney
  1997-09-30  0:00                   ` W. Wesley Groleau x4923
@ 1997-09-30  0:00                   ` Neil Wilson
  1997-09-30  0:00                     ` Stephen Leake
  1 sibling, 1 reply; 74+ messages in thread
From: Neil Wilson @ 1997-09-30  0:00 UTC (permalink / raw)



> In article <34316EC3.5B62@dynamite.com.au>, aebrain@dynamite.com.au
wrote:
> Yes, it's quite wrong to use a flag to terminate a while loop, instead of
> just using exit with a loop.  The idiom is, use an exit when the
> termination depends on what you read, eg
> 

[SNIP]

> 
> The classic example is, read some integers until the user types in the
value 0:
> 
> loop
> 
>    Read (N);
>    exit when N = 0;
> 
>    <process N>
> 
> end loop;

This can be fixed by using a 'half unroll'. Eiffel supports this:

loop
	file.read_integer
while file.last_integer != 0
	x.process (file.last_integer)
	file.read_integer
end -- loop

The introduction of the syntactically redundant 'loop' marker allows you to
flag the start of the loop initialisation section (technically the section
that sets up the loop invariant). The 'while' section is the loop itself
(which has to maintain the invariant, move forward the variant and do the
correct processing). 

Duplicating the 'read' command can be a bit of a pain, but in many
instances initialising the structure can be a different operation from the
actual iteration itself.


-- 
Neil Wilson (neil at aldur dot demon dot co dot uk)
Aldur Systems Ltd, UK




^ permalink raw reply	[flat|nested] 74+ messages in thread

* Re: Building blocks (Was: Design By Contract)
  1997-09-30  0:00                   ` Neil Wilson
@ 1997-09-30  0:00                     ` Stephen Leake
  0 siblings, 0 replies; 74+ messages in thread
From: Stephen Leake @ 1997-09-30  0:00 UTC (permalink / raw)



Neil Wilson wrote:
 
> [SNIP]
> 
> >
> > loop
> >
> >    Read (N);
> >    exit when N = 0;
> >
> >    <process N>
> >
> > end loop;
> 
> This can be fixed by using a 'half unroll'. Eiffel supports this:

why does it need to be "fixed"? what's wrong with it?

> loop
>         file.read_integer
> while file.last_integer != 0
>         x.process (file.last_integer)
>         file.read_integer
> end -- loop

Yech. Where does control transfer back to when end is reached? to 'loop'
or to 'while'? I'll take the Ada any day.

Perhaps Eiffel does not have "exit"
> 
> --
> Neil Wilson (neil at aldur dot demon dot co dot uk)
> Aldur Systems Ltd, UK

-- 
- Stephe




^ permalink raw reply	[flat|nested] 74+ messages in thread

* Re: Building blocks (Was: Design By Contract)
  1997-09-30  0:00                 ` Matthew Heaney
@ 1997-09-30  0:00                   ` W. Wesley Groleau x4923
  1997-09-30  0:00                     ` Matthew Heaney
  1997-10-01  0:00                     ` Alan E & Carmel J Brain
  1997-09-30  0:00                   ` Neil Wilson
  1 sibling, 2 replies; 74+ messages in thread
From: W. Wesley Groleau x4923 @ 1997-09-30  0:00 UTC (permalink / raw)



> Yes, it's quite wrong to use a flag to terminate a while loop, 
> instead of just using exit with a loop.  The idiom is, use an 
> exit when the termination depends on what you read, .....

Or to end a search when the item is found, or ...

Unfortunately, there are those who feel that not identifying the
loop termination at the beginning of the loop confuses the reader.
These folk are supported by a non-thoughtful reading of Ada Quality
and Style.  The "guidelines" (we all know that's another word for
"rules," right?) say to only exit from a plain loop, never from 
a 'while' or 'for'  So folks go through wierd contortions to avoid
"exit."  But the accompanying explanation clearly says that 
_readability_ is the criteria for choosing a loop construct.

-- 
----------------------------------------------------------------------
    Wes Groleau, Hughes Defense Communications, Fort Wayne, IN USA
Senior Software Engineer - AFATDS                  Tool-smith Wanna-be
                    wwgrol AT pseserv3.fw.hac.com

Don't send advertisements to this domain unless asked!  All disk space
on fw.hac.com hosts belongs to either Hughes Defense Communications or 
the United States government.  Using email to store YOUR advertising 
on them is trespassing!
----------------------------------------------------------------------




^ permalink raw reply	[flat|nested] 74+ messages in thread

* Re: Building blocks (Was: Design By Contract)
  1997-09-30  0:00                   ` W. Wesley Groleau x4923
@ 1997-09-30  0:00                     ` Matthew Heaney
  1997-10-01  0:00                     ` Alan E & Carmel J Brain
  1 sibling, 0 replies; 74+ messages in thread
From: Matthew Heaney @ 1997-09-30  0:00 UTC (permalink / raw)



In article <343149D9.6A30@pseserv3.fw.hac.com>, "W. Wesley Groleau x4923"
<wwgrol@pseserv3.fw.hac.com> wrote:


>Unfortunately, there are those who feel that not identifying the
>loop termination at the beginning of the loop confuses the reader.
>These folk are supported by a non-thoughtful reading of Ada Quality
>and Style.

Sometimes I think this book needs to be put out to pasture.

>The "guidelines" (we all know that's another word for
>"rules," right?) say to only exit from a plain loop, never from 
>a 'while' or 'for'  So folks go through wierd contortions to avoid
>"exit."  But the accompanying explanation clearly says that 
>_readability_ is the criteria for choosing a loop construct.

Well stated; thank you for pointing that out.  The reason for any
rule...um...I mean guideline is to promote understandability and ensure
correctness.  How often programmers forget that in their slavish adherence
to a style guide!

--------------------------------------------------------------------
Matthew Heaney
Software Development Consultant
<mailto:matthew_heaney@acm.org>
(818) 985-1271




^ permalink raw reply	[flat|nested] 74+ messages in thread

* Re: Building blocks (Was: Design By Contract)
  1997-09-30  0:00                   ` W. Wesley Groleau x4923
  1997-09-30  0:00                     ` Matthew Heaney
@ 1997-10-01  0:00                     ` Alan E & Carmel J Brain
  1 sibling, 0 replies; 74+ messages in thread
From: Alan E & Carmel J Brain @ 1997-10-01  0:00 UTC (permalink / raw)



W. Wesley Groleau x4923 wrote:
> 
> > Yes, it's quite wrong to use a flag to terminate a while loop,
> > instead of just using exit with a loop.  The idiom is, use an
> > exit when the termination depends on what you read, .....
> 
> Or to end a search when the item is found, or ...
> 
> Unfortunately, there are those who feel that not identifying the
> loop termination at the beginning of the loop confuses the reader.
> These folk are supported by a non-thoughtful reading of Ada Quality
> and Style.  The "guidelines" (we all know that's another word for
> "rules," right?) say to only exit from a plain loop, never from
> a 'while' or 'for'  So folks go through wierd contortions to avoid
> "exit."  But the accompanying explanation clearly says that
> _readability_ is the criteria for choosing a loop construct.

Concur. The "bottom line" is readability, that's a given (I hope..). In
this case, W. Wesley Groleau has provided pursuasive evidence that my
"while Unfinished" construct is less readable than his "exit" construct.
Although I'm not completely convinced, I am pursuaded that the "exit"
construct is superior, at least in this case. 

And I thought I was a true disciple of "egoless" review. There's nothing
like having a bunch of people expose one's coding failings in public,
calmly and correctly, to show how far one has to go. Still, I've learnt
something important I didn't know before, and that's worth any amount of
ego damage. My thanks to all concerned.
 
-- 
aebrain@dynamite.com.au     <> <>    How doth the little Crocodile
| Alan & Carmel Brain|      xxxxx       Improve his shining tail?
| Canberra Australia |  xxxxxHxHxxxxxx _MMMMMMMMM_MMMMMMMMM
 abrain@cs.adfa.oz.au  o OO*O^^^^O*OO o oo     oo oo     oo  
                    By pulling MAERKLIN Wagons, in 1/220 Scale





^ permalink raw reply	[flat|nested] 74+ messages in thread

* Re: Building blocks (Was: Design By Contract)
  1997-09-30  0:00               ` Alan E & Carmel J Brain
  1997-09-30  0:00                 ` Matthew Heaney
@ 1997-10-01  0:00                 ` Anonymous
  1997-10-01  0:00                   ` Paul M Gover
                                     ` (2 more replies)
  1 sibling, 3 replies; 74+ messages in thread
From: Anonymous @ 1997-10-01  0:00 UTC (permalink / raw)



<342A0AC6.2F2F@dynamite.com.au>
<199709251320.PAA03585@basement.replay.com>

On Tue, 30 Sep 1997 14:27:31 -0700, Alan E & Carmel J Brain
<aebrain@dynamite.com.au> wrote:

> Anonymous wrote:
> 
[big hunk deleted]
> > 2. Using while instead of loop/exit (ref. Ichbiah, Barnes, & Firth, "Ada
> > Launch," 1980 Dec 10, videotape, on why while was included in the
> > language).
> 
> I'd defend this one on style grounds, and believe the matter is
> religious. I have no access to this video. Any other sources? BTW
> perfectly willing to believe I'm wrong, I just want to know why...

This is an obscure reference, and I'd be the first to admit I've never
seen this addressed anywhere else, including Barnes' book. In the video,
which I had the good fortune to see in 1984, these three members of the
design team give a tutorial on Ada-80 (MIL-STD-1815) with plenty of
comments on "why". "While" was said to be undesireable because it tends
to require the use of negative logic, which is less readable than
positive logic:

Read : while not End_Of_File (Fred) loop

Read : loop
   exit Read when End_Of_File (Fred);

It was included in the language for the same reason as "goto": to
facilitate automated translation from languages that include the
feature.

Certainly "while" is preferred by those doing program correctness
proofs; all the techniques for this that I have seen have been for
"while" loops. Avoiding "while" does usually make for more readable
code. In this specific example, "while" requires a flag variable, which
is less readable than using "exit".

[hunk deleted]

> > 4. Unusual formatting of the if.
> 
> Style again. If expressible more clearly on one or two lines, use that,

Certainly, this is a style question. But the style used is not typical.

> Makes sense to me. OTOH there is a school of thought that eschews
> multiple exits. But that's another story. The point is, is that both
> versions show in a minimum number of lines the various options one has
> in Ada ( -83 at least, there are more in -95), which was the basic idea.

I'm aware of those who think multiple exits are bad. This is something
that came out of program correctness proving. However, when you look at
languages that only allow a single exit from a loop (Pascal, excluding
gotos) you find many common situations in which this results in
unreadable code. For this reason, "exit" and the possiblity of multiple
exits were included in Ada, and are considered acceptable by all
competent software engineers.

> 
> > "You brightly-colored, mealy-templed, cranberry-smelling, electric
> > donkey-bottom biters."
> 
> Was this meant personally? (<g> added for the hard-of-thinking) If so, I
> take exception! (That's supposed to be a pun.... never mind...)
> -- 

Of course this was meant personally. However, it doesn't come from me,
it comes from Monty Python, so you should take exception with them.

Jeff Carter  PGP:1024/440FBE21
My real e-mail address: ( carter @ innocon . com )
"I fart in your general direction."
Monty Python & the Holy Grail

Posted with Spam Hater - see
http://www.compulink.co.uk/~net-services/spam/




^ permalink raw reply	[flat|nested] 74+ messages in thread

* Re: Building blocks (Was: Design By Contract)
  1997-10-01  0:00                 ` Anonymous
@ 1997-10-01  0:00                   ` Paul M Gover
  1997-10-04  0:00                     ` Paul Johnson
  1997-10-01  0:00                   ` Joachim Durchholz
  1997-10-02  0:00                   ` Robert A Duff
  2 siblings, 1 reply; 74+ messages in thread
From: Paul M Gover @ 1997-10-01  0:00 UTC (permalink / raw)



Anonymous wrote:
> ... 
> > Makes sense to me. OTOH there is a school of thought that eschews
> > multiple exits. But that's another story. The point is, is that both
> > versions show in a minimum number of lines the various options one has
> > in Ada ( -83 at least, there are more in -95), which was the basic idea.
> 
> I'm aware of those who think multiple exits are bad. This is something
> that came out of program correctness proving. However, when you look at
> languages that only allow a single exit from a loop (Pascal, excluding
> gotos) you find many common situations in which this results in
> unreadable code. For this reason, "exit" and the possiblity of multiple
> exits were included in Ada, and are considered acceptable by all
> competent software engineers.
> ...

Some of my colleagues worked on a language which had a
	loop
		exit when
	end
construct, but with the restriction that each loop had
exactly one exit.  So it didn't allow multiple exits from
a loop, but still allowed:
	loop
		record = file.read()
	exit when file.eof()
		thing.accept(record)
	end
which keeps the code readable, and prevents duplication.
Does this have any impact on correctness proofs?
Presumably not much, as the loop can be converted to a
true while-loop by duplication.

(One of the while-loop problem is that for a tidy
record processing program you have to write
	record = file.read()
	Do while(~file.eof())
		thing.accept(record)
		record = file.read()
	End while
)

-- 
Paul Gover
IBM Warwick Development Group
Mumbling for myself, not IBM




^ permalink raw reply	[flat|nested] 74+ messages in thread

* Re: Building blocks (Was: Design By Contract)
  1997-10-01  0:00                 ` Anonymous
  1997-10-01  0:00                   ` Paul M Gover
@ 1997-10-01  0:00                   ` Joachim Durchholz
  1997-10-02  0:00                   ` Robert A Duff
  2 siblings, 0 replies; 74+ messages in thread
From: Joachim Durchholz @ 1997-10-01  0:00 UTC (permalink / raw)



Anonymous wrote:
> 
> Certainly "while" is preferred by those doing program correctness
> proofs; all the techniques for this that I have seen have been for
> "while" loops. Avoiding "while" does usually make for more readable
> code. In this specific example, "while" requires a flag variable,
> which is less readable than using "exit".

Actually positive/negative logic has nothing to do with why the
correctness guys prefer "while". What they want is that the termination
condition is at the start of the loop.
Actually Eiffel doesn't use "while", it uses "until". The correct syntax
is:

from
  -- loop initialization - arbitrary code
invariant
  -- here goes the loop invariant, a boolean expression that's
  -- true whenever execution reaches the top of the loop.
  -- loop invariants are useful to prove the correctness.
variant
  -- here the loop variant - an expression that will decrease
  -- with every iteration.
  -- loop variants are useful to prove that the loop will terminate.
until
  -- put your termination condition here
loop
  -- statements to be repeated
end

The "from" part is just syntactic sugar - leaving away the "from"
keyword won't change the semantics. Still it's useful to indicate the
beginning of the loop set-up code - it's often rather contrived to force
the loop invariant on the first go through the loop.

"invariant" and "variant" are the algorithm prover's tools. However,
proving and convincing somebody that it actually works is much the same,
i.e. these constructs are even useful when hacking. In particular if
you're in doubt wether your loop does exactly what it should, and wether
it terminates at all! Remember your first attempts at binary search in
an array?

The above construct has interesting properties (which will be well-known
to algorithm provers):
1. If a variant is present the code is guaranteed to terminate. Quite
useful for loops.
2. The loop invariant will be true at the start and at the end of the
code of the loop body.
3. When the loop terminates, both the invariant and the termination
condition will hold. Usually you don't have to look at the loop body to
understand what the loop is doing.
4. When reading a loop without the invariant stated, the worst problem
for understanding the code is this: We know numerous conditions that are
true when execution reaches the top of the loop, but we don't know which
of these conditions will be destroyed by the loop body. So we don't
understand which conditions will still hold for the second iteration,
i.e. we don't know what conditions the code of the loop body assumes.
This makes understanding the code extremely difficult - this is much
like reading the body of a routine without being allowed to look at the
parameter and local variable declarations (actually I think it's worse).

Regards,
Joachim
-- 
Please don't send unsolicited ads. (The @@ is for confusing spambots.)






^ permalink raw reply	[flat|nested] 74+ messages in thread

* Re: Building blocks (Was: Design By Contract)
  1997-10-02  0:00                   ` Robert A Duff
@ 1997-10-02  0:00                     ` Tucker Taft
  1997-10-02  0:00                       ` Matthew Heaney
  1997-10-03  0:00                     ` Stephen Leake
  1997-10-04  0:00                     ` Matthew Heaney
  2 siblings, 1 reply; 74+ messages in thread
From: Tucker Taft @ 1997-10-02  0:00 UTC (permalink / raw)



Robert A Duff (bobduff@world.std.com) wrote:

: ...
: By the way, speaking of negative logic, what do people think about
: negative logic in "if" statements?  I tend to try to reduce the number
: of "not"s in the code.  But other people tend to use some other
: heuristic, such as "do the normal case first" or "do unusual case
: first".  

FWIW, one of my heuristics is if one case is much shorter than the other,
do the shorter case first, as it is easier to see what is happening.
When you see something like:

     ... 200 lines
  else
     Do_Something;
  end if;

you can pretty easily lose track of what was the original condition
being tested.  Of course, another solution is to put a nice comment
after the "else" to say what is the condition governing the second case.
However, even if you put a comment on the else, I still find it clearer
to finish off the short case first, and then do the complicated one.

: - Bob

--
-Tucker Taft   stt@inmet.com   http://www.inmet.com/~stt/
Intermetrics, Inc.  Burlington, MA  USA




^ permalink raw reply	[flat|nested] 74+ messages in thread

* Re: Building blocks (Was: Design By Contract)
  1997-10-02  0:00                     ` Tucker Taft
@ 1997-10-02  0:00                       ` Matthew Heaney
  0 siblings, 0 replies; 74+ messages in thread
From: Matthew Heaney @ 1997-10-02  0:00 UTC (permalink / raw)



In article <EHG0o5.K03.0.-s@inmet.camb.inmet.com>,
stt@houdini.camb.inmet.com (Tucker Taft) wrote:

>Robert A Duff (bobduff@world.std.com) wrote:
>
>: ...
>: By the way, speaking of negative logic, what do people think about
>: negative logic in "if" statements?  I tend to try to reduce the number
>: of "not"s in the code.  But other people tend to use some other
>: heuristic, such as "do the normal case first" or "do unusual case
>: first".  
>
>FWIW, one of my heuristics is if one case is much shorter than the other,
>do the shorter case first, as it is easier to see what is happening.
>When you see something like:
>
>     ... 200 lines
>  else
>     Do_Something;
>  end if;

That about sums it up for me too.  I like to handle the special cases right
up in front.  That often means checking preconditions that aren't
expressable in Ada syntax (hint, hint).  I would have implemented Tuck's
example as

if not P then
   Do_Something;
   return;
end if;

...200 lines

One of the benefits of this approach is that it removes a level of nesting.

A simple example of a precondition check is a stack pop.  Instead of

procedure Pop (Stack : in out Bounded_Stack) is
begin
   if Stack.Top /= 0 then
      Stack.Top := Stack.Top - 1;
   else
      raise Stack_Empty;
   end if;
end;

I would do this as 

procedure Pop (Stack : in out Bounded_Stack) is
begin
   if Stack.Top = 0 then
      raise Stack_Empty;
   end if;

   Stack.Top := Stack.Top - 1;
end;

This is what I meant by "check preconditions at top of subprogram."  Get
the special cases out of the way.  Of course, you can also let Ada do the
check for you.  If the Top component is of type Natural, then

procedure Pop (Stack : in out Bounded_Stack) is
begin
   Stack.Top := Stack.Top - 1;
exception
   when Constraint_Error =>
      raise Stack_Empty;
end;

You have to be careful with this style, though; do too much in the
exception handler and you can get burned by RM 11.6 subtleties.

Of course, it would be really cool if I could declare Pop as

procedure Pop (Stack : in out Root_Stack)
precondition
   Not_Empty: Length (Stack) > 0;
end Pop;

and then Ada could check the precondition for me.

David Luckham wrote a paper (and a whole annotation language) describing
exception annotations, something like:

procedure Pop (Stack : in out Root_Stack)
exception
   when Length (Stack) = 0 => raise Stack_Empty;
end Pop;

Maybe we can look into this for the next language update, hmmmm?

--------------------------------------------------------------------
Matthew Heaney
Software Development Consultant
<mailto:matthew_heaney@acm.org>
(818) 985-1271




^ permalink raw reply	[flat|nested] 74+ messages in thread

* Re: Building blocks (Was: Design By Contract)
  1997-10-01  0:00                 ` Anonymous
  1997-10-01  0:00                   ` Paul M Gover
  1997-10-01  0:00                   ` Joachim Durchholz
@ 1997-10-02  0:00                   ` Robert A Duff
  1997-10-02  0:00                     ` Tucker Taft
                                       ` (2 more replies)
  2 siblings, 3 replies; 74+ messages in thread
From: Robert A Duff @ 1997-10-02  0:00 UTC (permalink / raw)



In article <199710011402.QAA02444@basement.replay.com>,
Anonymous <nobody@REPLAY.COM> wrote:
>..."While" was said to be undesireable because it tends
>to require the use of negative logic, which is less readable than
>positive logic:

It requires negative logic in *this* case, because there happens to be
an End_Of_File function, rather than (say) a Within_File function.
Sure, *some* while loops require negative logic, but some don't:

    "while X in Some_Subtype loop" vs. "exit when X not in Some_Subtype"

    "while X <= Max loop" vs "exit when X > Max"
    
    "while Is_Good(X) loop" vs "exit when Is_Evil(X)"

I always prefer a while loop if there is exactly one exit condition at
the start.  I think this is usually the case -- I would guess I've
written perhaps 10 times as many while loops as loops-with-exit in my
life (in Ada, I mean -- other languages sometimes have different
features).

>Read : while not End_Of_File (Fred) loop
>
>Read : loop
>   exit Read when End_Of_File (Fred);
>
>It was included in the language for the same reason as "goto": to
>facilitate automated translation from languages that include the
>feature.

I find this statement rather dubious.  For one thing, I can't believe
that Ichbiah et al were that down on while loops.  (I can believe they
advocated avoiding "not"s, but not all while loops need nots.)  For
another thing, there's a trivial transformation from "while" to
loop-with-exit-at-the-start, so how is this necessary for automated
translation?  In the goto case, the transformation is not so trivial.

>Certainly "while" is preferred by those doing program correctness
>proofs; all the techniques for this that I have seen have been for
>"while" loops. Avoiding "while" does usually make for more readable
>code. In this specific example, "while" requires a flag variable, which
>is less readable than using "exit".

I certainly agree that using an "exit" is better than having extra flags
and whatnot.  But I think this is the less common case -- in the most
common case, "while" does just fine.  I certainly don't believe that
"while considered harmful"!

I'm also a bit suspicious of "program correctness proof" arguments, if
the argument pushes toward writing less readable code (or lots more
code).  In such cases, it seems like the proof techniques are lacking,
not the code one is trying to prove something about.  (E.g. if somebody
says (and they have), don't use generics, because they're hard to prove
correct, and that means I have to write 17 different Stack packages,
instead of one generic one, I blame the proof techniques, not the
generic.)

>...For this reason, "exit" and the possiblity of multiple
>exits were included in Ada, and are considered acceptable by all
>competent software engineers.

OK, then I'll claim that "while" is considered acceptable by all
competent software engineers.  ;-)  Is this a statement about what the
authorities say, or is it a definition of who's competent and who
isn't?  ;-)

By the way, speaking of negative logic, what do people think about
negative logic in "if" statements?  I tend to try to reduce the number
of "not"s in the code.  But other people tend to use some other
heuristic, such as "do the normal case first" or "do unusual case
first".  For example:

    if Is_Evil(X) then
        print error message;
    else
        ... -- 37 lines of code doing the normal thing
    end if;

vs

    if not Is_Evil(X) then
        ... -- 37 lines of code doing the normal thing
    else
        print error message;
    end if;

vs

    if Is_Good(X) then
        ... -- 37 lines of code doing the normal thing
    else
        print error message;
    end if;

vs

    if not Is_Good(X) then
        print error message;
    else
        ... -- 37 lines of code doing the normal thing
    end if;

Or perhaps even:

    if Is_Evil(X) then
        print error message;
        return;
    end if;
    ... -- 37 lines of code doing the normal thing

- Bob




^ permalink raw reply	[flat|nested] 74+ messages in thread

* Re: Building blocks (Was: Design By Contract)
  1997-10-02  0:00                   ` Robert A Duff
  1997-10-02  0:00                     ` Tucker Taft
@ 1997-10-03  0:00                     ` Stephen Leake
  1997-10-04  0:00                     ` Matthew Heaney
  2 siblings, 0 replies; 74+ messages in thread
From: Stephen Leake @ 1997-10-03  0:00 UTC (permalink / raw)



Robert A Duff wrote:

> By the way, speaking of negative logic, what do people think about
> negative logic in "if" statements?  I tend to try to reduce the number
> of "not"s in the code.  But other people tend to use some other
> heuristic, such as "do the normal case first" or "do unusual case
> first".  For example:
> 
>     if Is_Evil(X) then
>         print error message;
>     else
>         ... -- 37 lines of code doing the normal thing
>     end if;

I prefer this style; put the easily handled case first.

> 
> vs
> 
>     if not Is_Evil(X) then
>         ... -- 37 lines of code doing the normal thing
>     else
>         print error message;
>     end if;
> 
> vs
> 
>     if Is_Good(X) then
>         ... -- 37 lines of code doing the normal thing
>     else
>         print error message;
>     end if;
> 
> vs
> 
>     if not Is_Good(X) then
>         print error message;
>     else
>         ... -- 37 lines of code doing the normal thing
>     end if;
> 
> Or perhaps even:
> 
>     if Is_Evil(X) then
>         print error message;
>         return;
>     end if;
>     ... -- 37 lines of code doing the normal thing

I also do this, especially when the 'return' gets me out of more than
one layer of 'if'

> 
> - Bob

-- 
- Stephe




^ permalink raw reply	[flat|nested] 74+ messages in thread

* Re: Building blocks (Was: Design By Contract)
  1997-09-23  0:00             ` Veli-Pekka Nousiainen
@ 1997-10-03  0:00               ` Robert I. Eachus
  1997-10-04  0:00                 ` Paul Johnson
  0 siblings, 1 reply; 74+ messages in thread
From: Robert I. Eachus @ 1997-10-03  0:00 UTC (permalink / raw)



In article <01bcc7f6$638b7f60$108142c1@Yeif-1.eiffel.fi> "Veli-Pekka Nousiainen" <vp.nousiainen@remove_this_eiffel.fi> writes:

 > It is clear to me that postconditioning is missing in all other languages
 > exept Eiffel (Sather???). If all you need is comments, then my old
 > hex-assembler for an 8-bit processor is all O-O with DbC, I just comment...

   Actually Ada does have a quite well defined concept of pre- and
post- conditions for subprograms.  However, they are implicit rather
than defined as part of the syntax.  This guarentees that the
conditions are always true, but it makes it hard to add complex
postconditions.

   for example:

   subtype NNFloat is range 0..Float'Last;
   function Square_Root(F: in NNFloat) return NNFloat;

   guarentees that if no exception is raised that F is non-negative
(pre-condition) and the return value is also non-negative.

   It also promises that all task depending on Square_Root have
terminated, that all Controlled objects within Square_Root have been
finalized, etc.  Note that this second group of post-conditions is
true whether or not an exception is raised, unless, of course, the
finalization action raises an exception not handled locally--very bad
form.

   However, defining types and subtypes is Ada is a much more awkward
way of checking different postconditions than is possible in Eiffel.
And also, the definitions of the subtypes and the body of the
subprogram are often distant from the declaration.  Thus the
habit/practice of documenting the actual pre and post conditions in
comments when not obvious from the declaration.

   Which is better?  I prefer the Ada approach, where you can, with a
little bit of caution, always count on the value of the object meeting 
all of the rules for such objects, rather than associating the
conditions with the last subprogram called.  However in both Ada and
Eiffel, the normal case is that the post-conditions for operations of
a class or type are all identical.  In that case, it matters little
which approach is used.
--

					Robert I. Eachus

with Standard_Disclaimer;
use  Standard_Disclaimer;
function Message (Text: in Clever_Ideas) return Better_Ideas is...




^ permalink raw reply	[flat|nested] 74+ messages in thread

* Re: Building blocks (Was: Design By Contract)
  1997-10-03  0:00               ` Robert I. Eachus
@ 1997-10-04  0:00                 ` Paul Johnson
  1997-10-14  0:00                   ` Robert I. Eachus
  0 siblings, 1 reply; 74+ messages in thread
From: Paul Johnson @ 1997-10-04  0:00 UTC (permalink / raw)



In article <EACHUS.97Oct3164342@spectre.mitre.org>, "Robert I. Eachus"
<eachus@spectre.mitre.org> writes

>   Actually Ada does have a quite well defined concept of pre- and
>post- conditions for subprograms.  However, they are implicit rather
>than defined as part of the syntax.  This guarentees that the
>conditions are always true, but it makes it hard to add complex
>postconditions.

Yes, sort of.

[Positive subrange example deleted]

The problem is that it doesn't let you say things like

   item: T is
      require
         not empty

>   Which is better?  I prefer the Ada approach, where you can, with a
>little bit of caution, always count on the value of the object meeting 
>all of the rules for such objects,

You can count on it for Eiffel as well: invariants state this kind of
thing.

Paul.
--------------------------------+---------------------------------
Paul Johnson                    | You are lost in a maze of twisty
Email: Paul@treetop.demon.co.uk | little standards, all different.
       paul.johnson@gecm.com    |




^ permalink raw reply	[flat|nested] 74+ messages in thread

* Re: Building blocks (Was: Design By Contract)
  1997-10-02  0:00                   ` Robert A Duff
  1997-10-02  0:00                     ` Tucker Taft
  1997-10-03  0:00                     ` Stephen Leake
@ 1997-10-04  0:00                     ` Matthew Heaney
  1997-10-07  0:00                       ` Robert A Duff
  2 siblings, 1 reply; 74+ messages in thread
From: Matthew Heaney @ 1997-10-04  0:00 UTC (permalink / raw)



In article <EHFvt5.D1G@world.std.com>, bobduff@world.std.com (Robert A
Duff) wrote:


>By the way, speaking of negative logic, what do people think about
>negative logic in "if" statements?  I tend to try to reduce the number
>of "not"s in the code.  But other people tend to use some other
>heuristic, such as "do the normal case first" or "do unusual case
>first".  For example:

I like to handle the exceptional case first, and return early.

>Or perhaps even:
>
>    if Is_Evil(X) then
>        print error message;
>        return;
>    end if;
>    ... -- 37 lines of code doing the normal thing

This one gets my vote.

--------------------------------------------------------------------
Matthew Heaney
Software Development Consultant
<mailto:matthew_heaney@acm.org>
(818) 985-1271




^ permalink raw reply	[flat|nested] 74+ messages in thread

* Re: Building blocks (Was: Design By Contract)
  1997-10-01  0:00                   ` Paul M Gover
@ 1997-10-04  0:00                     ` Paul Johnson
  1997-10-04  0:00                       ` Matthew Heaney
  0 siblings, 1 reply; 74+ messages in thread
From: Paul Johnson @ 1997-10-04  0:00 UTC (permalink / raw)



In article <3432788C.E35@uk.ibm.com>, Paul M Gover
<Paul_Gover@uk.ibm.com> writes

>(One of the while-loop problem is that for a tidy
>record processing program you have to write
>       record = file.read()
>       Do while(~file.eof())
>               thing.accept(record)
>               record = file.read()
>       End while
>)

I know that this was an aside, but it still puzzles me.  Surely it will
be wrong if the file is empty: there will be no record to read.  The
correct version (in Eiffel) would be

   from file.open("foo") until file.eof loop
      thing.accept (file.record)
   end -- loop

If you have to read a dummy record before file.eof becomes valid then
you have a badly designed file object.

Paul.

--------------------------------+---------------------------------
Paul Johnson                    | You are lost in a maze of twisty
Email: Paul@treetop.demon.co.uk | little standards, all different.
       paul.johnson@gecm.com    |




^ permalink raw reply	[flat|nested] 74+ messages in thread

* Re: Building blocks (Was: Design By Contract)
  1997-10-04  0:00                     ` Paul Johnson
@ 1997-10-04  0:00                       ` Matthew Heaney
  1997-10-15  0:00                         ` Paul Johnson
  0 siblings, 1 reply; 74+ messages in thread
From: Matthew Heaney @ 1997-10-04  0:00 UTC (permalink / raw)



In article <PdRYMWAQ1cN0Iw4X@treetop.demon.co.uk>, Paul Johnson
<Paul@treetop.demon.co.uk> wrote:

>>(One of the while-loop problem is that for a tidy
>>record processing program you have to write
>>       record = file.read()
>>       Do while(~file.eof())
>>               thing.accept(record)
>>               record = file.read()
>>       End while
>>)
>
>I know that this was an aside, but it still puzzles me.  Surely it will
>be wrong if the file is empty: there will be no record to read.  The
>correct version (in Eiffel) would be
>
>   from file.open("foo") until file.eof loop
>      thing.accept (file.record)
>   end -- loop
>
>If you have to read a dummy record before file.eof becomes valid then
>you have a badly designed file object.

That's the idiom in Ada too:

while not End_Of_File (F) loop
   Read (F, X);
   <do something with X>;
end loop;

I think the original example, though, was this: read some numbers from the
user interactively, process each one at a time, and stop processing when
the user enters a zero.  In Ada, it would be 

loop
   Read (N);
   exit when N = 0;
   <do something with N>;
end loop;

This is a very clean solution, and in the Soloway paper, they showed that
there were fewer errors using this loop structure compared to a loop which
disallows an exit from the middle.  Something like:

Read (N);
while N /= 0 loop
   <do something with N>
   Read (N);
end loop;

The issue here is that the read statement must be written twice.  Exiting
from the middle is a more natural idiom for certain problems. 

So don't assume that there's a "badly designed" file, because we might not
be literally talking about a file.  That the loop termination depends on
what you've read (the "dummy" value) is a common occurrence, and the
simplest loop idiom in this case is:

loop
   <get value>
   exit when <value is special>
   <process value>
end loop;

A while loop is more complex and error prone solution for this type of
problem.  Soloway showed that there was a statistically significant
difference between two populations, one using a test-at-the-top, and the
other using a test-in-the-middle, with the latter group having fewer
errors.  The reference is:

Coginitive Strategies and Looping Constructs: An Empirical Study
Elliot Soloway et al
CACM, Vol. 26, No. 11, Nov 83, p. 853 - 860


A typical example of termination depending on input is a scanner.  If
you're scanning an identifier (say), then you exit when you've read some
whitespace:

Scan_Identifier:
loop
   <get character>
   exit Scan_Identifier when <char is whitespace>
   <buffer char>
end loop Scan_Identifier;

<process Identifier token>

Another common idiom is a linear search.  When you find the item you're
looking for, bail out:

Find_Item:
declare
   Found : Boolean := False;
   Position : Positive range Items'Range;
begin
   for Index in Items'Range loop
      if Items (Index) = Item then
         Position := Index;
         Found := True;

         exit;
      end if;
   end loop;

   if Found then
      <do something>
   else
      <do something else>
   end if;
end Find_Item;

Exiting from the middle of a loop also shows up in functions as an early return:

function Position (Items : Item_Array; Item : T) return Natural is
begin
   for Index in Items'Range loop
      if Items (Index) = Item then
         return Index;
      end if;
   end loop;

   return 0;  -- means Item not found
end;

In none of these cases is the "file" badly designed.

--------------------------------------------------------------------
Matthew Heaney
Software Development Consultant
<mailto:matthew_heaney@acm.org>
(818) 985-1271




^ permalink raw reply	[flat|nested] 74+ messages in thread

* Re: Building blocks (Was: Design By Contract)
  1997-10-04  0:00                     ` Matthew Heaney
@ 1997-10-07  0:00                       ` Robert A Duff
  0 siblings, 0 replies; 74+ messages in thread
From: Robert A Duff @ 1997-10-07  0:00 UTC (permalink / raw)



In article <mheaney-ya023680000410971755550001@news.ni.net>,
Matthew Heaney <mheaney@ni.net> wrote:
>I like to handle the exceptional case first, and return early.
>
>>Or perhaps even:
>>
>>    if Is_Evil(X) then
>>        print error message;
>>        return;
>>    end if;
>>    ... -- 37 lines of code doing the normal thing
>
>This one gets my vote.

Yeah, I often do that sort of thing, too.  But I've been burned more
than once by return_statements in this way: I want to add some code that
gets executed just before the procedure leaves, and I add it at the end
without noticing that there's a return_statement buried somewhere near
the beginning (perhaps a couple of nesting-levels deep).  In *that*
regard, a goto is better than a return, because you can add code just
after the label.

- Bob




^ permalink raw reply	[flat|nested] 74+ messages in thread

* Re: Building blocks (Was: Design By Contract)
  1997-10-04  0:00                 ` Paul Johnson
@ 1997-10-14  0:00                   ` Robert I. Eachus
  0 siblings, 0 replies; 74+ messages in thread
From: Robert I. Eachus @ 1997-10-14  0:00 UTC (permalink / raw)



In article <J87JkUA6zdN0Iwrm@treetop.demon.co.uk> Paul Johnson <Paul@treetop.demon.co.uk> writes:

  > The problem is that it doesn't let you say things like

  >    item: T is
  >	 require
  >	    not empty

    Actually Ada does allow this type of restriction as well but only
for certain classes of types.

   (I said:)

   >   Which is better?  I prefer the Ada approach, where you can, with a
   >little bit of caution, always count on the value of the object meeting 
   >all of the rules for such objects,

   (Back to Paul:)

   > You can count on it for Eiffel as well: invariants state this kind of
   > thing.

   Not quite.  The difference is that in Eiffel, invariants are
checked at discrete points, while in Ada the corresponding checks
occur before each assignment, so that a valid object never becomes
invalid.

   Now, as such this is not a criticism of the Eiffel approach.  There
is a lot of code you couldn't write if some checks were done when
components of an object were modified.  With the Ada approach, you
have to do a whole record assignment if you change the discriminant of
a record, so there is the overhead of creating and copying the new
value, even if it is only slightly different from the old.

   As a result, you end up designing your objects differently for the
two different approaches.  I prefer the designs which match the Ada
idiom, where the structural effects of this are at a very low level.
But it is just that, a preference.  (And yes, I have had cases where
the "pure" Ada design worked just fine, but had horrible performance.
The fixes often include things like replacing an array of records with
an array of pointers to records, or vice-versa.  But the nice feature
is that you can make these low level performance changes AFTER
debugging your code.  You may be removing some of the lifeboats, but
at least they were there when you tested the package initially.)

   
--

					Robert I. Eachus

with Standard_Disclaimer;
use  Standard_Disclaimer;
function Message (Text: in Clever_Ideas) return Better_Ideas is...




^ permalink raw reply	[flat|nested] 74+ messages in thread

* Re: Building blocks (Was: Design By Contract)
  1997-10-04  0:00                       ` Matthew Heaney
@ 1997-10-15  0:00                         ` Paul Johnson
  1997-10-15  0:00                           ` Matthew Heaney
                                             ` (2 more replies)
  0 siblings, 3 replies; 74+ messages in thread
From: Paul Johnson @ 1997-10-15  0:00 UTC (permalink / raw)



In article <mheaney-ya023680000410970119430001@news.ni.net>, Matthew
Heaney <mheaney@ni.net> writes

>In article <PdRYMWAQ1cN0Iw4X@treetop.demon.co.uk>, Paul Johnson
><Paul@treetop.demon.co.uk> wrote:

>>I know that this was an aside, but it still puzzles me.  Surely it will
>>be wrong if the file is empty: there will be no record to read.  The
>>correct version (in Eiffel) would be
>>
>>   from file.open("foo") until file.eof loop
>>      thing.accept (file.record)
>>   end -- loop

[...]

>I think the original example, though, was this: read some numbers from the
>user interactively, process each one at a time, and stop processing when
>the user enters a zero.  In Ada, it would be 

[...]

>A while loop is more complex and error prone solution for this type of
>problem.  Soloway showed that there was a statistically significant
>difference between two populations, one using a test-at-the-top, and the
>other using a test-in-the-middle, with the latter group having fewer
>errors.  The reference is:
>
>Coginitive Strategies and Looping Constructs: An Empirical Study
>Elliot Soloway et al
>CACM, Vol. 26, No. 11, Nov 83, p. 853 - 860

[Examples of when you want to do this in real life deleted.]

Hmm.  Interesting.

I agree that the repeated read (or whatever instruction) before the loop
and at the end is a bad idea.  Quite apart from the Soloway experiment,
it is duplicating code.

OTOH I wonder if the situation might be reversed in real life situations
with deeply nested structures.  I'm rather dubious of small, neat coding
experiments such as Soloway's.  While they are the best handle we have
on the facts, I worry that in an attempt to come up with a controllable,
repeatable, and above all feasible experiment, they abstract out too
much complexity.  After all, it is complexity that makes programming
difficult.

I recall the great AT&T telephone crash in the late 80s (87?).  It was
caused by a bug where a programmer had mistaken the scope of a "break"
instruction, and hence miscalculated the target of the resulting jump.
Now thats not a statistical experiment, but its a worrying data point.
I wonder what would happen if Soloway's experiment were repeated with
more complex problems involving nested loops.

(I haven't actually read the paper, but I'll see if our library has it
tomorrow).

Paul.

--------------------------------+---------------------------------
Paul Johnson                    | You are lost in a maze of twisty
Email: Paul@treetop.demon.co.uk | little standards, all different.
       paul.johnson@gecm.com    |




^ permalink raw reply	[flat|nested] 74+ messages in thread

* Re: Building blocks (Was: Design By Contract)
  1997-10-15  0:00                         ` Paul Johnson
@ 1997-10-15  0:00                           ` Matthew Heaney
  1997-10-16  0:00                             ` Joachim Durchholz
  1997-10-16  0:00                           ` Joachim Durchholz
  1997-10-22  0:00                           ` Reimer Behrends
  2 siblings, 1 reply; 74+ messages in thread
From: Matthew Heaney @ 1997-10-15  0:00 UTC (permalink / raw)



In article <5w3FnzA6KRR0Iwt+@treetop.demon.co.uk>, Paul Johnson
<Paul@treetop.demon.co.uk> wrote:

>I recall the great AT&T telephone crash in the late 80s (87?).  It was
>caused by a bug where a programmer had mistaken the scope of a "break"
>instruction, and hence miscalculated the target of the resulting jump.
>Now thats not a statistical experiment, but its a worrying data point.
>I wonder what would happen if Soloway's experiment were repeated with
>more complex problems involving nested loops.

In Ada, the programmer has control over the loop to which the exit applies,
by using loop labels; the C programmer can't do this without using an
explicit goto. 

A common idiom is to implement a finite state machine using loops, where
each loop represents a different state.  A "main" loop keeps the entire
thing going until termination is requested.  For example, I just wrote a
simple little test program to read in some data I typed in at the terminal,
and process it.  

begin
   Main:
   loop
      Put ("Enter: ");

      Get_Input:
      loop
         begin
            Get (Data);
            exit Get_Input;
         exception
            when End_Error =>
                exit Main;
            when Data_Error | Constraint_Error =>
                Skip_Line;
                Put ("Bad data; try again: ");
         end;
      end loop Get_Input;

      <process Data>
   end loop Main;

This is yet another example of the read-test-process loop idiom.

Think of the Get_Input loop as a state: you leave the state when you have
good data (and then go process it), or you leave the state (and the outer,
Main state too) because you're done with your testing (by pressing CNTL-D
on UNIX or CNTL-Z on VMS).  You stay in the Get_Input state as long as the
user enters bad data (wrong type or out-of-range).

Note how the exit statement explicitly identifies the loop to which it
applies: either Get_Input or Main.

--------------------------------------------------------------------
Matthew Heaney
Software Development Consultant
<mailto:matthew_heaney@acm.org>
(818) 985-1271




^ permalink raw reply	[flat|nested] 74+ messages in thread

* Re: Building blocks (Was: Design By Contract)
  1997-10-15  0:00                         ` Paul Johnson
  1997-10-15  0:00                           ` Matthew Heaney
@ 1997-10-16  0:00                           ` Joachim Durchholz
  1997-10-22  0:00                           ` Reimer Behrends
  2 siblings, 0 replies; 74+ messages in thread
From: Joachim Durchholz @ 1997-10-16  0:00 UTC (permalink / raw)



Paul Johnson wrote:
> 
> I agree that the repeated read (or whatever instruction) before the
> loop and at the end is a bad idea.  Quite apart from the Soloway
> experiment, it is duplicating code.

Me too (on both accounts).

> OTOH I wonder if the situation might be reversed in real life
> situations with deeply nested structures.  I'm rather dubious of
> small, neat coding experiments such as Soloway's.

I can support that from personal experience. Whenever code involved
'break'ing out from several nesting levels deep, it was rather
unreadable and difficult to decipher.

However, there's a middle ground between "break only at top of loop" and
"break everywhere within a loop": "break anywhere at the top level
within a loop". A syntax for this might look like this:

  loop
    ...
  until <condition>
    ...
  until <condition>
    ...
  end loop

so one could write

  loop
    <read a value>
  until value = '0'
    <process value>
  end loop

This avoids both the obfuscation from breaking out from deeply nested
code *and* the code duplication necessary if the termination condition
is forced to the top of the loop.

To satisfy those who are concerned with making sure that the loop does
what it has to, and terminates (hi Eiffelists!), the syntax could be set
up as follows:

<loop> ::=
  from
    <loop set-up statements - syntactic sugar>
  loop
    <loop statement>
    <loop statement>
    ...
  end

<loop statement> ::=
  [invariant <condition>] -- must be true on every iteration
  [variant <expression>]  -- must decrease on every iteration
                          -- must not decrease beyond a given threshold
                          -- (this ensures that the loop terminates)
  until <expression>      -- termination condition

<loop statement> ::=
  <statement>             -- normal statements are allowed, too :)

i.e. within the loop body, an arbitrary number of
  invariant ...
  variant ...
  until ...
sequences can be placed, with invariant and variant optional. The
postcondition of the loop would be the OR of all the invariants ANDed
with their respective "until" conditions, so having too many loop exits
will make checking and understanding the loop more work, so the number
of loop exits should be small. Actually I'm not sure wether such a
syntax shouldn't be limited to a single exit - I have very rarely felt
the need for mutliple loop exits, and a bit of inconvenience in rare
cases is always worth a better language structure.

Regards,
Joachim
-- 
Please don't send unsolicited ads. (The @@ is for confusing spambots.)






^ permalink raw reply	[flat|nested] 74+ messages in thread

* Re: Building blocks (Was: Design By Contract)
  1997-10-15  0:00                           ` Matthew Heaney
@ 1997-10-16  0:00                             ` Joachim Durchholz
  1997-10-17  0:00                               ` Robert I. Eachus
  0 siblings, 1 reply; 74+ messages in thread
From: Joachim Durchholz @ 1997-10-16  0:00 UTC (permalink / raw)



Fie, what's this! Exceptions used for flow control...

Regards,
Joachim
-- 
Please don't send unsolicited ads. (The @@ is for confusing spambots.)






^ permalink raw reply	[flat|nested] 74+ messages in thread

* Re: Building blocks (Was: Design By Contract)
  1997-10-16  0:00                             ` Joachim Durchholz
@ 1997-10-17  0:00                               ` Robert I. Eachus
  0 siblings, 0 replies; 74+ messages in thread
From: Robert I. Eachus @ 1997-10-17  0:00 UTC (permalink / raw)



In article <34467890.243549EE@munich.netsurf.de> Joachim Durchholz <joachim.durchholz@munich.netsurf.de> writes:

  > Fie, what's this! Exceptions used for flow control...

   No, a code fragment where errors are explicitly handled.  If you
examine the code more closely you will notice that the inner loop has
an exit statement associated with accepting valid input.  You go
around that loop again if you have bad input.  ONE of the ways to end
up rerunning the input loop is if you handle an exception, there are
usually several others.  This is a common idiom.

   Now in Ada, it may be right to avoid using exceptions for flow
control, but that doesn't mean you should throw the exceptions on the
floor or ignore them.  And once you handle the error, of course you
want to return to the proper state.  So any well implemented state
machine in Ada will have exception handlers, and even gotos in some of
them.  But it doesn't mean that that path is expected to be taken
outside of testing.




--

					Robert I. Eachus

with Standard_Disclaimer;
use  Standard_Disclaimer;
function Message (Text: in Clever_Ideas) return Better_Ideas is...




^ permalink raw reply	[flat|nested] 74+ messages in thread

* Re: Building blocks (Was: Design By Contract)
  1997-10-15  0:00                         ` Paul Johnson
  1997-10-15  0:00                           ` Matthew Heaney
  1997-10-16  0:00                           ` Joachim Durchholz
@ 1997-10-22  0:00                           ` Reimer Behrends
  2 siblings, 0 replies; 74+ messages in thread
From: Reimer Behrends @ 1997-10-22  0:00 UTC (permalink / raw)



Paul Johnson (Paul@treetop.demon.co.uk) wrote:
[Discussion of exit-at-top vs. exit-anywhere.]
: Hmm.  Interesting.
: 
: I agree that the repeated read (or whatever instruction) before the loop
: and at the end is a bad idea.  Quite apart from the Soloway experiment,
: it is duplicating code.

Yes, but ... see below.

: OTOH I wonder if the situation might be reversed in real life situations
: with deeply nested structures.  I'm rather dubious of small, neat coding
: experiments such as Soloway's.  While they are the best handle we have
: on the facts, I worry that in an attempt to come up with a controllable,
: repeatable, and above all feasible experiment, they abstract out too
: much complexity.  After all, it is complexity that makes programming
: difficult.

You have a point here, I think. It is worth noting that the example
discussed not only was a toy program, but also had a couple of bugs in
it (didn't work for empty or non-numerical input). This may be perfectly
acceptable for prototyping, of course, but not for industrial-strength
code.

The general problem is that if your task cannot be suitably expressed
with one control structure, you have basically two options:

	(1) "Rewire" the control flow.
	(2) Think of suitable abstractions instead of expressing
	    something directly.

The most general approach to (1) is to use goto or one of its
watered-down variants (break, continue, Sather style iterators, etc.).
The problem with them is that if only you use them often enough you lose
the clarity of single-entry, single-exit structures. It becomes hard to
understand the code or produce test cases that provide adequate
coverage. This is (aside from general gotos) particularly extreme if you
have multi-level breaks, breaks inside deeply nested if-statements, etc.

It should be noted, however, that just removing such constructs from the
syntax of the language doesn't necessarily alleviate the problem. You
can always simulate them with boolean variables, and code that makes
ample use of this "solution" will probably be even harder to understand.
That doesn't mean that you boolean variables shouldn't be used as
convenient abbreviations for complex conditions, just not to simulate
gotos.

Using (2) appears like the cleaner solution, and it probably is. After
all, didn't structured programming teach years ago that if we have code
that is long, complex, or repeated in more than one place, we should try
to encapsulate suitable parts in subroutines? It should be noticed,
however, that writing such abstractions can be more work initially
(which hopefully pays off due to code reuse and making testing and
maintenance easier) and relies on a compiler that is capable of decent
automatic inlining of code to ensure suitable efficiency for certain
applications.

Another point is not only choosing to use abstractions, but also to
choose _suitable_ abstractions. For instance, much of the problem in the
original example (reading integers and adding them until a zero is
encountered, I think) stem from the fact that "read" is not really a
good abstraction for complex computations. Like the "x++" operator in C,
it lumps two marginally related operations together without a good
reason.  This becomes much clearer when you try to use it with more
advanced parsing methods.  For instance, with shift-reduce parsers, you
will always have to undo the read operation when doing a reduce.
Providing separate primitives for advancing the input stream and
checking the current token not only work much better for that case, they
are also easier extend if you suddenly need a lookahead > 1.

A similar case can be made for handwritten LL(k) parsers. Much of their
bad reputation (besides the fact that it _is_ easier and safer to write
a parser using a tool) stems from the fact that with the traditional
read operations grammar rules don't map as nicely to code as when you
have both an advance and a lookahead operation, because the entry
into/exit from the code for a rule often does not correspond to the
current position of the input stream.

I seem to remember that Bertrand Meyer suggested somewhere that a
routine should either query the state of an object, or change it, but
never both (i.e. function vs. procedure). I think we have a good example
here why to avoid the latter approach.

Of course, with an appropriate INTEGER_SCANNER class the code is no less
clear than the original example:

	from
	  scanner.start(...)
	  sum := 0
	until scanner.stopped or else scanner.data = 0 loop
	  sum := sum + scanner.data
	  scanner.advance
	end

This also takes care of end-of-file and error conditions that can occur.

Yes, "start" and "advance" will probably call a common routine. That's
only natural, as they both have to ensure the class invariant is right
in a similar fashion. And it doesn't duplicate code.

[...]

				Reimer Behrends





^ permalink raw reply	[flat|nested] 74+ messages in thread

end of thread, other threads:[~1997-10-22  0:00 UTC | newest]

Thread overview: 74+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
1997-09-09  0:00 Building blocks (Was: Design By Contract) Marc Wachowitz
1997-09-15  0:00 ` Joachim Durchholz
1997-09-17  0:00 ` Paul Johnson
1997-09-18  0:00   ` Stephen Leake
1997-09-18  0:00     ` W. Wesley Groleau x4923
1997-09-21  0:00       ` Matthew Heaney
1997-09-18  0:00     ` Mark L. Fussell
     [not found]       ` <11861963wnr@eiffel.demon.co.uk>
1997-09-19  0:00         ` Mark L. Fussell
1997-09-19  0:00       ` Robert A Duff
1997-09-20  0:00         ` Joachim Durchholz
1997-09-22  0:00           ` Matthew Heaney
1997-09-23  0:00             ` Veli-Pekka Nousiainen
1997-10-03  0:00               ` Robert I. Eachus
1997-10-04  0:00                 ` Paul Johnson
1997-10-14  0:00                   ` Robert I. Eachus
1997-09-23  0:00             ` Joachim Durchholz
1997-09-23  0:00           ` Jon S Anthony
1997-09-24  0:00           ` Alan E & Carmel J Brain
1997-09-25  0:00             ` Anonymous
1997-09-30  0:00               ` Alan E & Carmel J Brain
1997-09-30  0:00                 ` Matthew Heaney
1997-09-30  0:00                   ` W. Wesley Groleau x4923
1997-09-30  0:00                     ` Matthew Heaney
1997-10-01  0:00                     ` Alan E & Carmel J Brain
1997-09-30  0:00                   ` Neil Wilson
1997-09-30  0:00                     ` Stephen Leake
1997-10-01  0:00                 ` Anonymous
1997-10-01  0:00                   ` Paul M Gover
1997-10-04  0:00                     ` Paul Johnson
1997-10-04  0:00                       ` Matthew Heaney
1997-10-15  0:00                         ` Paul Johnson
1997-10-15  0:00                           ` Matthew Heaney
1997-10-16  0:00                             ` Joachim Durchholz
1997-10-17  0:00                               ` Robert I. Eachus
1997-10-16  0:00                           ` Joachim Durchholz
1997-10-22  0:00                           ` Reimer Behrends
1997-10-01  0:00                   ` Joachim Durchholz
1997-10-02  0:00                   ` Robert A Duff
1997-10-02  0:00                     ` Tucker Taft
1997-10-02  0:00                       ` Matthew Heaney
1997-10-03  0:00                     ` Stephen Leake
1997-10-04  0:00                     ` Matthew Heaney
1997-10-07  0:00                       ` Robert A Duff
1997-09-24  0:00           ` Richard A. O'Keefe
1997-09-19  0:00       ` Jon S Anthony
1997-09-23  0:00         ` Mark L. Fussell
1997-09-18  0:00   ` Jon S Anthony
1997-09-18  0:00   ` Robert Dewar
  -- strict thread matches above, loose matches on Subject: below --
1997-09-11  0:00 Robert Dewar
1997-09-09  0:00 Marc Wachowitz
1997-09-02  0:00 Design By Contract Jon S Anthony
     [not found] ` <JSA.97Sep3201329@alexandria.organon.com>
1997-09-04  0:00   ` Paul Johnson
     [not found]     ` <5un58u$9ih$1@gonzo.sun3.iaf.nl>
1997-09-06  0:00       ` Building blocks (Was: Design By Contract) Joachim Durchholz
1997-09-08  0:00       ` Paul Johnson
1997-09-08  0:00         ` Brian Rogoff
1997-09-09  0:00           ` Matthew Heaney
1997-09-09  0:00             ` Brian Rogoff
1997-09-09  0:00             ` W. Wesley Groleau x4923
1997-09-10  0:00               ` Robert A Duff
1997-09-12  0:00                 ` Jon S Anthony
1997-09-10  0:00             ` Robert Dewar
1997-09-12  0:00               ` Paul Johnson
1997-09-14  0:00                 ` Robert Dewar
1997-09-14  0:00                 ` Robert Dewar
1997-09-15  0:00                   ` John G. Volan
1997-09-14  0:00                 ` Robert Dewar
1997-09-12  0:00               ` Jon S Anthony
1997-09-12  0:00                 ` Robert Dewar
1997-09-16  0:00                   ` Brian Rogoff
1997-09-10  0:00             ` Paul Johnson
1997-09-10  0:00               ` Darren New
1997-09-10  0:00               ` Matthew Heaney
1997-09-09  0:00           ` W. Wesley Groleau x4923
1997-09-09  0:00           ` Veli-Pekka Nousiainen
1997-09-09  0:00             ` Jon S Anthony
1997-09-09  0:00           ` Veli-Pekka Nousiainen

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox