Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

Modular Protection vs Assertions ...

1 view
Skip to first unread message

bravegag

unread,
Jul 28, 2007, 9:40:53 AM7/28/07
to
Hi all,

After reading Bertrand Meyer's OOSC book I find a little bit blurred
the line between using proper exception declarations in public methods
vs using asserts for precondition checking.

It is confusing to me the fact that:

- Bertrand remarks the need of "Modular Protection" which is not
clearly stated but I assume it also applies to Software-to-Software
communication i.e. between modules. Therefore module boundaries or
module public API must rely on proper exception handling for argument
checking and in general precondition checking (instead of using
assertions for that purpose). I find "Modular Protection" to be
somehow similar to "Defensive Programming".

- On the other hand Bertrand Meyer also remarks a valid thing which is
that excessive checking can be very harmful performance-wise.
Therefore recommends using assertions that are enabled only during
development, testing and debugging and disabled once the system is
delivered in production.

Another fact is that (somehow contrary to Bertrand Meyers view) Sun
assert usage guideline dictate that "Do not use assertions for
argument checking in public methods" see
http://java.sun.com/j2se/1.5.0/docs/guide/language/assert.html#usage

So I can only make the conclusion that:

- Assertions should be used even in public methods as long as those
methods are not part of the public API of a module i.e. assertions are
not an input checking mechanism for module boundaries. Bertrand Meyer
has a section in the chapter "Design by Contract" and the headline is
precisely that but then he remarks it is intended only for Human-to-
Software communication or Outside-World-to-Software communication.

- Proper exception handling should be the solution to use within
module boundaries so that not only the public API of a module
establishes a contract but also allows the client modules to
gracefully retry or at least recover from serious faults as
consequence of precondition violations in production time.

I would greatly appreciate your feedback or insights into this subject
or even pointers to further discussion.

I have seen situations where faults may lead to a total software chaos
just because they used assertions within module boundaries for input
checking rather than proper exception handling.

TIA,
Regards,
Giovanni

Colin LeMahieu

unread,
Jul 29, 2007, 4:08:25 AM7/29/07
to
Exceptions are used to handle cases where the failure result could not
have been predicted beforehand. A network communications failure
cannot be tested for and you can only observe its occurrence once it
has happened.

Contracts are used to reduce the domain and range of a function in to
terms valid for that function. A range constraint on the function
is_even(source: INTEGER) would be result implies source \\ 2 = 0. A
domain constraint on the function sqrt(source: REAL) would be source >
0. It can be determined beforehand that source should should not be
negative or that an even number should have no remainder when divided
by two.

Contracts should be fleshed out in debugging and testing. Exceptions
can occur during normal program execution and should be anticipated
and able to recover but only used to recover from things that could
not have been tested beforehand.

I hope that clears up their distinct uses.

On Jul 28, 8:40 am, bravegag <brave...@gmail.com> wrote:
> Hi all,
>
> After reading Bertrand Meyer's OOSC book I find a little bit blurred
> the line between using proper exception declarations in public methods
> vs using asserts for precondition checking.
>
> It is confusing to me the fact that:
>
> - Bertrand remarks the need of "Modular Protection" which is not
> clearly stated but I assume it also applies to Software-to-Software
> communication i.e. between modules. Therefore module boundaries or
> module public API must rely on proper exception handling for argument
> checking and in general precondition checking (instead of using
> assertions for that purpose). I find "Modular Protection" to be
> somehow similar to "Defensive Programming".
>
> - On the other hand Bertrand Meyer also remarks a valid thing which is
> that excessive checking can be very harmful performance-wise.
> Therefore recommends using assertions that are enabled only during
> development, testing and debugging and disabled once the system is
> delivered in production.
>
> Another fact is that (somehow contrary to Bertrand Meyers view) Sun
> assert usage guideline dictate that "Do not use assertions for

> argument checking in public methods" seehttp://java.sun.com/j2se/1.5.0/docs/guide/language/assert.html#usage

llothar

unread,
Jul 29, 2007, 7:24:56 AM7/29/07
to
On 29 Jul., 15:08, Colin LeMahieu <clemah...@gmail.com> wrote:
> Exceptions are used to handle cases where the failure result could not
> have been predicted beforehand. A network communications failure
> cannot be tested for and you can only observe its occurrence once it
> has happened.

But a network error it is so often that you shouldn't use exceptions
here either. Don't use exceptions as another control flow (except if
you have serious reasons to do so).

> Contracts are used to reduce the domain and range of a function in to
> terms valid for that function. A range constraint on the function
> is_even(source: INTEGER) would be result implies source \\ 2 = 0. A

Sorry this is a result constraint and not a rande constraint.

But the main sentence in your posting is correct:

Ulrich Windl

unread,
Jul 31, 2007, 2:54:06 AM7/31/07
to
bravegag <brav...@gmail.com> writes:

> Hi all,
>
> After reading Bertrand Meyer's OOSC book I find a little bit blurred
> the line between using proper exception declarations in public methods
> vs using asserts for precondition checking.
>
> It is confusing to me the fact that:
>
> - Bertrand remarks the need of "Modular Protection" which is not
> clearly stated but I assume it also applies to Software-to-Software
> communication i.e. between modules. Therefore module boundaries or
> module public API must rely on proper exception handling for argument
> checking and in general precondition checking (instead of using
> assertions for that purpose). I find "Modular Protection" to be
> somehow similar to "Defensive Programming".

As Meyer points out, a correct program does not pass invalid parameters (where
the precondition would be violated). The task to find bad callers is during
development, not during field-use. Therefore the precondition checks are
normally off. If the precondition is violated, all guarantees are lost. The
routine _may_ raise an exception, but it's not a MUST.

>
> - On the other hand Bertrand Meyer also remarks a valid thing which is
> that excessive checking can be very harmful performance-wise.
> Therefore recommends using assertions that are enabled only during
> development, testing and debugging and disabled once the system is
> delivered in production.

Correct.

>
> Another fact is that (somehow contrary to Bertrand Meyers view) Sun
> assert usage guideline dictate that "Do not use assertions for
> argument checking in public methods" see
> http://java.sun.com/j2se/1.5.0/docs/guide/language/assert.html#usage
>
> So I can only make the conclusion that:
>
> - Assertions should be used even in public methods as long as those
> methods are not part of the public API of a module i.e. assertions are
> not an input checking mechanism for module boundaries. Bertrand Meyer

Remember: A violated assertion (like a precondition) will always terminate the
program. Usually you cannot write a correct handler to recover from that. You
must fix the program bug instead.

> has a section in the chapter "Design by Contract" and the headline is
> precisely that but then he remarks it is intended only for Human-to-
> Software communication or Outside-World-to-Software communication.
>
> - Proper exception handling should be the solution to use within
> module boundaries so that not only the public API of a module
> establishes a contract but also allows the client modules to
> gracefully retry or at least recover from serious faults as
> consequence of precondition violations in production time.

You can always put your "if .. then raise()" there. Eiffel has no "Modules"
other than classes. You are suggesting that the called routine should signal
the caller that it has made a mistake to give the caller a chance to recover
from its error? The caller should know that it's wrong, even before
calling. That's the argumentation of Mr. Meyer I think (s/Mr./Prof. Dr./).

>
> I would greatly appreciate your feedback or insights into this subject
> or even pointers to further discussion.
>
> I have seen situations where faults may lead to a total software chaos
> just because they used assertions within module boundaries for input
> checking rather than proper exception handling.

See the Ariane case: The error output ("test pattern") of one module was used
as valid input for another module. It would have been better if there hadn't
been an exception at all ;-)

"He, who presses the button has the responsibility, and not the manufacturer
of the button"

Regards,
Ulrich

Ulrich Windl

unread,
Jul 31, 2007, 2:59:00 AM7/31/07
to
llothar <llo...@web.de> writes:

> On 29 Jul., 15:08, Colin LeMahieu <clemah...@gmail.com> wrote:
> > Exceptions are used to handle cases where the failure result could not
> > have been predicted beforehand. A network communications failure
> > cannot be tested for and you can only observe its occurrence once it
> > has happened.
>
> But a network error it is so often that you shouldn't use exceptions
> here either. Don't use exceptions as another control flow (except if
> you have serious reasons to do so).

Define "network error" not as CSMA/CD error (like a lost packet, a mangled
packet), but as a high level error, like an aborted TCP connection. Those are
quite rare (in a sane configuration). And I think it's much preferrable to
handle an unexpected problem via an exception rather than testing for an error
after every write to the network. (Similar for writing to files)

[...]

Ulrich

llothar

unread,
Jul 31, 2007, 2:26:53 PM7/31/07
to
On 31 Jul., 13:59, Ulrich Windl <Ulrich.Wi...@RZ.Uni-Regensburg.DE>
wrote:

> Define "network error" not as CSMA/CD error (like a lost packet, a mangled
> packet), but as a high level error, like an aborted TCP connection. Those are
> quite rare (in a sane configuration). And I think it's much preferrable to
> handle an unexpected problem via an exception rather than testing for an error
> after every write to the network. (Similar for writing to files)

Well i still prefer something like the C standard library here.
Setting an error code on the first time we see it and then simply
ignore all operations on the socket and let the user check it when it
is necessary.

At the moment i'm writing a webserver and there it works fine without
any exception. Well maybe this simple request/response thing is much
too simple.

bravegag

unread,
Aug 1, 2007, 2:57:33 AM8/1/07
to
Hi Colin,

Many thanks for your feedback.

On Jul 29, 10:08 am, Colin LeMahieu <clemah...@gmail.com> wrote:
> Exceptions are used to handle cases where the failure result could not
> have been predicted beforehand. A network communications failure
> cannot be tested for and you can only observe its occurrence once it
> has happened.
>

You have somehow mentioned it in this paragraph which is my point
about module boundaries.

Suppose you develop a new Socket library API. You can and will test
all invalid cases that you could foresee as invalid uses of your
library. Optimally you would offer an extensive test-coverage and
examples of use of the library. Still your library as a separate
module DOES NOT know by whom and how it is going to be used in the
future. It is a reusable class library API right? so future and
unknown clients of this library:

- Must not know the library guts to be able to use it, which is the
case when they while using it start receiving any kind of assertion
violations from deep in the library code. There should be a defensive
layer around i.e. what Bertrand calls filter modules that ensure the
input is valid in the first place. But the reaction to invalid input
are Exceptions not assertions.

- Have the ability to recover at runtime from violations of the filter
modules otherwise unknown clients will not have any chance to recover
from filter module invalid input violations.

I personally would have a very bad feeling delivering such a reusable
class library
API (what I call module) to clients knowing they:

- Will have to test and debug my library finding out assetion
violations deep in my code rather that knowing upfront all invalid
input situations via exception in the module boundaries "throws"
declarations in Java.

- Will not have any chance to recover from possible assertion
(preconditions) violations which are not clearly stated in the
publicly visible API interfaces.

Many thanks for the interesting discussion.

Best Regards,
Giovanni

bravegag

unread,
Aug 1, 2007, 3:14:09 AM8/1/07
to
Hi Ulrich,

Many thanks for your feedback.

On Jul 31, 8:54 am, Ulrich Windl <Ulrich.Wi...@RZ.Uni-Regensburg.DE>
wrote:

> As Meyer points out, a correct program does not pass invalid parameters (where
> the precondition would be violated). The task to find bad callers is during
> development, not during field-use. Therefore the precondition checks are
> normally off. If the precondition is violated, all guarantees are lost. The
> routine _may_ raise an exception, but it's not a MUST.
>

Indeed, when developing a normal software system you find bad callers
during development time whereas when developing a reusable class
library API e.g. Patterns Library, Network Library, Data Structures
library you do not know what the bad callers are gonna be. That's why
I was asking in the OP if what Bertrand remarks as "Modular
Protection" will also apply to Software-to-Software communication e.g.
developing the third party library.

I am currently the developer of a reusable java class library and this
is a major question:

- Shall I leave my potential client modules on their own? they will
have to figure out what my precondition violations are. This is the
case when using assertions.

- Shall I provide a strict defensive layer i.e. filter modules as
Bertrand calls it so that whenever my library gets in control I know
for sure that the input is valid?

Best regards,
Giovanni

llothar

unread,
Aug 1, 2007, 4:39:38 AM8/1/07
to
> - Shall I leave my potential client modules on their own? they will
> have to figure out what my precondition violations are. This is the
> case when using assertions.

They have to learn your library, yes. If you pass invalid input to
some internal classes then it is a failure of your program (the
calling client class) you have to assure that this will not happen.

If your library is buggy then an exception is not a real surprise for
your client.

> - Shall I provide a strict defensive layer i.e. filter modules as
> Bertrand calls it so that whenever my library gets in control I know
> for sure that the input is valid?

In reality, yes you have to add defensive layer. I often write my code
like this

function foo(x: INTEGER) is
require
x > 0
do
if x > 0 then
... do something
end
end

Of couse you can't do this always, you need to design your code in
this way. The reason is simple and very pragmatic. You can't find all
the problems during development and testing. Crashing your app will
hurt your sales, catching defensive (and praying to the black Lord
that it will not be too serious) is okay.

This is for MY PROBLEM DOMAIN, which has nothing to do with air
traffic or nuclear power plants.

In fact for my software i do a A:B test (not 50%:50% but more 10%:90%
where 10% of customers get precondition checking versions and 90% are
getting much faster definensive ones). Remember all Eiffel compilers
have a slowdown of 5-8x times when precondition are checked. The only
hope you have is that you can drop the defensive layer some day.

And there is another very pragmatic problem. In an ACE file you define
on a class level what should be checked which is of course really
stupid. Eiffel should define levels of security on subsystems not on
classes. For example i only have the option to check the precondition
of STRING.item or not. But what i want is that if i think i have a
correct subsystem i want that eiffel does not check the preconditions
of STRING.item in my subsystem but everywhere else. AFAIK no compiler
offers this at the moment.

As you can see with ISE/Eiffel Studio frequent crashs and problems as
an example (since version 3.6) there is a gap between what Mr. Meyer
was teaching us and reality.

llothar

unread,
Aug 1, 2007, 4:42:00 AM8/1/07
to
> - Will not have any chance to recover from possible assertion
> (preconditions) violations which are not clearly stated in the
> publicly visible API interfaces.

Redesign and document your API.

Maybe one of the most important things i learned was better
specification of API's. It's now always a pain to read C++ or Java
libraries.

Colin LeMahieu

unread,
Aug 1, 2007, 10:27:23 AM8/1/07
to

I think this stems from a misunderstanding of responsibility
assignment associated with preconditions and postconditions.
Precondition violations mean the caller has a bug. Postcondition
violations mean the calee has a bug. If you have completely tested
your public library, all internal calls would not have possibility of
tripping another internal assertion. Each feature with a contract
states "if you give me this 'require', I can give you this 'ensure'"

There will never be such a thing as a *deep assertion violation*
Every assertion violation should occur at the API boundries between
unknown -> library and it should only be a precondition violation
which would point the blame at the unknown. If there is an assertion
violation *deep* in a library call such as: unknown -> library ->
(library -> library) between two library calls, the blame is not on
the unknown, it's actually on your library. Your library passed
invalid input to another library call, you may say "well that's
because the unknown passed in bad input." But according to your
contracts that's not so. The violation didn't occur at: (unknown ->
library) -> library -> library, it occurred at: unknown -> library ->
(library -> library) meaning according to your library *definition*
the input from unknown to library was valid but your library crashed,
you have a bug, not them.

Ulrich Windl

unread,
Aug 2, 2007, 4:47:43 AM8/2/07
to
bravegag <brav...@gmail.com> writes:

[...]


> - Shall I leave my potential client modules on their own? they will
> have to figure out what my precondition violations are. This is the
> case when using assertions.

Actually it's "their precondition violations", not "yours". That is they (the
callers) are responsible for violationg the precondition. For communicating
modules (not just one Eiffel system), one could allow the "true" precondition
and add an "if" to catch calling errors. In classical C libraries, a
free(NULL) will not catch that, because that would be an extra test for every
function call. Maybe you want that.

>
> - Shall I provide a strict defensive layer i.e. filter modules as
> Bertrand calls it so that whenever my library gets in control I know
> for sure that the input is valid?

Sounds like a good idea: Maybe implement your class the usual Eiffel way, then
add a class around it that allows any precondition, checks for valid
arguments, then call the implementation if the parameters were OK; otherwise
signal an error (raise exception (the Java way), or return a failure code (the
C way)).

Ulrich

0 new messages