Re: Exceptions
- From: Niklas Holsti <niklas.holsti@xxxxxxxxxxxxxxx>
- Date: Tue, 11 Dec 2007 15:21:57 +0200
Dmitry A. Kazakov wrote:
On Mon, 10 Dec 2007 22:02:55 +0200, Niklas Holsti wrote:
One reason for the large number of application-defined exceptions in this application may be that it uses a lot of functional-style programming with functions that return objects with run-time constraints (eg. unconstrained array types). Such functions cannot easily use error codes and must use exceptions to signal problems.
I tend use End_Error, Use_Error, Data_Error in such cases.
I don't like that at all, because in my mind End_Error etc. are associated with Ada IO, not with my application -- their meaning (semantics :-) is not appropriate, and I don't want to be Humpty Dumpty and make them mean what I want them to mean.
Of course, if the function in question actually is reading a file, and fails because the file ends at an unexpected point, then End_Error could be appropriate. But for a function that has no connection with IO I would never "reuse" End_Error just to avoid declaring a specific exception.
The question is
how many different exceptions may propagate from a set of closures used in
one context. Not that many, so my guess is that one need not so many
different exceptions.
But surely one of the main points of a contract is to show what a caller may have to do, to handle the propagated exceptions. To "overload" one exception (such as End_Error) with many different meanings, perhaps requiring different handling, would make the caller's job difficult.
I agree that the number of different exceptions that are usefully propagated from most subprograms is generally small, because the caller does not have enough understanding of the possible exceptional situtations in the callee to be able to handle many different exceptions in specific ways.
Clearly most subprograms have no exception handlers at all and thus propagate all exceptions raised in them or in their callees.
Yes, this why I don't believe in the argument of abundant exception
handlers spoiling each and other program block. I don't see why contracts
should change anything here.
I think all subprograms would need contracts (to specify the possibly propagated exceptions), not just the few subprograms that have exception handlers. The contract has to be in the subprogram declaration, while the presence or absence of exception handlers is a property of the body.
Exception contracts could become a considerable part of the source code, especially if they would have to include the "always possible" exceptions like Storage_Error and in the absence of any SPARK-like analysis to exclude impossible exceptions from the contract.
A typical scenario: A lazy (let's say busy) programmer designs some set of
low-level primitives raising some exceptions. Then he starts to write a
middle layer that reuses those primitives, not necessarily in exactly this
order, but anyway. The exceptions of the middle layer are different, and of
course, the lower level exceptions do not propagate out the middle layer.
At this point he has already forgot most of when and what the lower level
raises. He remembers the exceptions E3 and E10, but the rest is vanished.
He decides whether to use "when others" but has no clear idea what to do
there, so maybe he places something looking more or less appropriate there
hoping that the debugging phase will shed more light on the issue, or just
drop it, depending on how much coffee he already had. The rest is obvious.
Does it sound familiar?
Not really. I use informal exception contracts (in comments describing each and every subprogram), so I have not experienced that kind of mess. But I have mistakenly omitted a necessary handler once or twice, generally when the raise-to-handle distance has been very large (fatal or semi-fatal exception).
Now a contracted exceptions scenario: The programmer contracts a
middle-layer subprogram as non-propagating anything he does not want to. He
does not write any handlers, just compiles the code. The compiler complains
about E1. Aha - he says, where that E1 comes from? This repeats until all
low-level exceptions are caught, *understood* and handled.
That would be ideal, and very much in the Ada spirit. But I can see why it is not an easy addition to Ada.
The main problem I see in contracted exceptions is the problem with layered architectures where some intermediate layers are general/generic and not application-specific....
I think there is no simple answer to this. What could help IMO is:
1. Conditional exception contracts (for things like Storage_Error and
exceptions from the closures)
2. Inheritable exception contracts (to be able to refer to a group of
exceptions from another subprogram)
3. Making exceptions an ordered type with some kind of tree-like distance.
4. Renaming/delegation of exceptions.
And perhaps also
5. Exceptions as formal generic parameters.
--
Niklas Holsti
Tidorum Ltd
niklas holsti tidorum fi
. @ .
.
- Follow-Ups:
- Re: Exceptions
- From: Dmitry A. Kazakov
- Re: Exceptions
- From: Randy Brukardt
- Re: Exceptions
- References:
- Exceptions
- From: shaunpatterson
- Re: Exceptions
- From: Adam Beneschan
- Re: Exceptions
- From: Simon Wright
- Re: Exceptions
- From: Robert A Duff
- Re: Exceptions
- From: Georg Bauhaus
- Re: Exceptions
- From: Dmitry A. Kazakov
- Re: Exceptions
- From: Niklas Holsti
- Re: Exceptions
- From: Dmitry A. Kazakov
- Re: Exceptions
- From: Niklas Holsti
- Re: Exceptions
- From: Dmitry A. Kazakov
- Exceptions
- Prev by Date: Re: Exceptions
- Next by Date: Re: Exceptions
- Previous by thread: Re: Exceptions
- Next by thread: Re: Exceptions
- Index(es):
Relevant Pages
|