Velocity Reviews - Computer Hardware Reviews

Velocity Reviews > Newsgroups > Programming > Java > use of assert in Java [vs. exceptions]

Reply
Thread Tools

use of assert in Java [vs. exceptions]

 
 
Giovanni Azua
Guest
Posts: n/a
 
      05-30-2009
Hello,

This is a follow up to the thread "Where should I throw RuntimeException".
At some point the topic regarding the use of assertions took over that
thread discussion.

Before moving into the concrete arguments I wanted to present the following
definitions by Bertrand Meyer:

Defensive programming: "A technique of fighting potential errors by making
every module check for many possible consistency conditions, even if this
causes redundancy of checks performed by clients and suppliers. Contradicts
Design by Contract." [1, p1195]

Design by Contract: "A method of software construction that designs the
components of a system so that they will cooperate on the basis of precisely
defined contracts. See also: defensive programming." [1, p1195]

"Assertion Violation rule (1) A run-time assertion violation is the
manifestation of a bug in the software." [1, p346]

The key in the defensive programming definition is "check". It doesn't
really matter what is done after encountering the problem either throwing
exceptions or programming an alternate way e.g. Math.sqrt that handles the
special case of negative input by returning Double.NaN. Please note that
neither Eiffel "require" nor the Java "assert" for verification of pre
conditions would fall under the category "check", by definition Design by
Contract (DbC) is not a check, they are enabled only optionally and for
discovering programming errors. Granted that Java assert feature is a small
subset of what Eiffel DbC offers [3, p15 "So, is it like 'assert.h'"].

The point I was defending was that Sun's commended way to use assertions was
too categorical "Do not use assertions to check the parameters of a public
method" [2]. The reasoning for my discrepancy towards that rule is that
programs should not handle pre condition violations that are rooted in
programming errors by means of exceptions e.g. IllegalArgumentException.
However, the case of user input validation is a good use-case for using
IllegalArgumentException. In general, exceptions are meant to be handled
programmatically. You can't nor should recover from programming errors but
rather *fix* them e.g.

Defensive alternative A:

public void defensiveMethod(...) throws IllegalArgumentException {
// first checks
if (/* some input programming error condition */) {
throw IllegalArgumentException("Caught just another bug");
}

// some checks
// some more checks ...

// now we are "safe", do the real business
}

// a possible client
try {
defensiveMethod(...);
}
catch (IllegalArgumentException exception) {
// what can you possibly do here? maybe we could ...
//
// - retrieve class name of the caller
// - get the author name out of the java file
// - send her an email complaining to FIX her code!
}

vs.

DbC alternative B:

public void dbCMethod(...) {
// assert-based pre condition verification. Assertions
// will be disabled once all programming errors are
// corrected

// assert-based class invariant verification

// do the real business

// assert-based class invariant verification

// assert-based post-condition verification
}

Defensive programming as defined by Bertrand Meyer above yields the
following negative consequences in software engineering:

- degrades performance
- predates reliability
- increases complexity
- provides only a subjective sense of safety
- increases code duplication, redundancy
- scatters concerns across disparate layers

A few excerpts from Bertrand Meyer's book:

"Non-Redundancy principle: Under no circumstances shall the body of a
routine ever test for the routine's precondition." [1, p343] For the example
that depicts such case he writes "is not just unnecessary but unacceptable"
[1, p343]

"... complexity is the major enemy of quality. When we bring in this
concern, possibly redundant checks do not appear so harmless any more!
Extrapolated to the thousands of routines of a medium -size system (or the
tens or hundreds of thousands of routines of a larger one), the if x < 0
then ... of sqrt, innocuous at first sight, begins to look like a monster of
useless complexity. By adding possibly redundant checks, you add more
software; more software means more complexity, and in particular more
sources of conditions that could go wrong; hence the need for more checks,
meaning more software; and so on ad infinitum. If we start on this road only
one thing is certain: we will never obtain reliability. The more we write,
the more we will have to write." [1, p344]

"Aside from performance considerations, however, the principal reason to
distrust defensive programming is simply our goal of getting the best
possible reliability. For a system of any significant size the individual
quality of the various elements involved is not enough; what will count most
is the guarantee that for every interaction between two elements there is an
explicit roster of mutual obligations and benefits - the contract. Hence the
Zen-style paradox of our conclusion: that to get more reliability the best
policy is often to check less." [1, p345]

"Lew" <(E-Mail Removed)> wrote
>The method [Math.sqrt] must handle the illegal input. No amount
>of concern for "performance" relieves it of responsibility to
>handle a negative input.
>

wow it is even scary! like the perfect example, hey! I will let Bertrand
Meyer respond to you here ...

"Such a comment, however, comes from a microscopic understanding of
reliability, focused on individual software elements such as the sqrt
routine. If we restrict our view to the narrow world of sqrt, then the
routine seems more robust with the extra test than without it. But the world
of a system is not restricted to a routine; it contains a multitude of
routines in a multitude of classes. To obtain reliable systems we must go
from the microscopic view to a macroscopic view encompassing the entire
architecture." [1, p344]

"Lew" <(E-Mail Removed)> wrote
>According to you, that would never happen.
>How do you guarantee that? What would the
>result be?
>

"if the client's part of the contract is not fulfilled, that is to say if
the call does not satisfy the precondition, then the class is not bound by
the postcondition. In this case the routine may do what it pleases: return
any value; loop indefinitely without returning a value; or even crash the
execution in some wild way. This is the case in which (in reference to the
discussion at the beginning of this chapter) 'the customer is wrong'." [1,
p343]

Once there is a programming error that lead to pre condition violations in
production, it does not really matter what the preferred paradigm is, either
DbC or Defensive Programming, the result will be either a crash or any
behavior that differs to that stated in the software specification.

An excellent example on how the defensive programming approach i.e. check
and throw exception can not only give a very subjective sense of safety but
also become "the problem" is the 500 million loss case of Ariane 5 "The
exception was due to a floating-point error: a conversion from a 64-bit
integer to a 16-bit signed integer, which should only have been applied to a
number less than 2^15, was erroneously applied to a greater number,
representing the "horizontal bias" of the flight. There was no explicit
exception handler to catch the exception, so it followed the usual fate of
uncaught exceptions and crashed the entire software, hence the on-board
computers, hence the mission. " [4]

From my professional experience I have personally seen and worked with both
approaches. I have seen software developed for the Java platform that could
not afford bugs but neither compromise in reliability nor performance, a
real-time high-frequency trading arbitrage solution using the closest DbC
you can have in Java. I can't recall one single e.g.
IndexOutOfBoundsException in production and most pre condition verifications
were done via asserts and these were only enabled during testing.

I hope all the excerpts and explanations illustrate my point.

"Lew" <(E-Mail Removed)> wrote
>According to you, that would never happen.
>How do you guarantee that? What would the
>result be?
>

The group of SE at ETH Zurich works on several answers to these questions
e.g.

- Formal methods [5]
- Contract-based automatic testing [6]

Soon there is this very very nice and interesting LASER Summer School where
Bertrand Meyer himself will present some of these concepts
[http://se.inf.ethz.ch/laser/2009/index.php]. I might join btw

For perfectjpattern I deliverately chose to stick to the way Sun commends
regarding the use of assertions, I would like my project perfectjpattern to
be accepted and not rejected by the Java community. I know the concepts of
DbC and how implementing those concepts in Java via assertions might be
outrageous for experienced developers (hey! at first it happened to me too)
but it can't hurt to have a wider picture and use this knowledge to make
more educated design decisions.

Related discussions:

"Where should I throw RuntimeException"
[http://groups.google.com/group/comp....419d1a0522e92]

"Assertions vs Exceptions" posted to this group in 2007
[http://groups.google.com/group/comp....43f9aa1?hl=en]

"Modular Protection vs Assertions" posted to the comp.lang.eiffel group in
2007
[http://groups.google.com/group/comp....571d8d33088a1]

Best regards,
Giovanni

[1] Programming with Assertions
[http://java.sun.com/j2se/1.5.0/docs/...e/assert.html]
[2] Object Oriented Software Construction 2nd Edition Bertrand Meyer
[http://www.amazon.com/Object-Oriente...672117&sr=8-1]
[3] OOSC course slides "Design by Contract"
[http://se.inf.ethz.ch/teaching/ss200...1_dbc_1up.pdf]
[4] The lessons of Ariane
[http://archive.eiffel.com/doc/manual...ane/page.html]
[5] Formal methods [http://en.wikipedia.org/wiki/Formal_methods]
[6] Automatic Testing based on Design by Contract
[http://www.mathematik.uni-ulm.de/sai...des/ciupa.pdf]



 
Reply With Quote
 
 
 
 
Roedy Green
Guest
Posts: n/a
 
      05-30-2009
The way I see it is this:

Assertions are to defend against programming bugs.

Exceptions are to defend against bad or freakish data.

I think we programmers tend to underuse assertions. They can detect
subtle problems before the bug shows up as obvious insane program
behaviour. You can leave assertions in place without speed penalty by
not using an -ea on the command line.

--
Roedy Green Canadian Mind Products
http://mindprod.com

"Everybody’s worried about stopping terrorism. Well, there’s a really easy way: stop participating in it."
~ Noam Chomsky
 
Reply With Quote
 
 
 
 
Arved Sandstrom
Guest
Posts: n/a
 
      05-30-2009
Giovanni Azua wrote:
[ SNIP ]

> The point I was defending was that Sun's commended way to use assertions was
> too categorical "Do not use assertions to check the parameters of a public
> method" [2]. The reasoning for my discrepancy towards that rule is that
> programs should not handle pre condition violations that are rooted in
> programming errors by means of exceptions e.g. IllegalArgumentException.
> However, the case of user input validation is a good use-case for using
> IllegalArgumentException. In general, exceptions are meant to be handled
> programmatically. You can't nor should recover from programming errors but
> rather *fix* them e.g.
>
> Defensive alternative A:
>
> public void defensiveMethod(...) throws IllegalArgumentException {
> // first checks
> if (/* some input programming error condition */) {
> throw IllegalArgumentException("Caught just another bug");
> }
>
> // some checks
> // some more checks ...
>
> // now we are "safe", do the real business
> }
>
> // a possible client
> try {
> defensiveMethod(...);
> }
> catch (IllegalArgumentException exception) {
> // what can you possibly do here? maybe we could ...
> //
> // - retrieve class name of the caller
> // - get the author name out of the java file
> // - send her an email complaining to FIX her code!
> }
>
> vs.
>
> DbC alternative B:
>
> public void dbCMethod(...) {
> // assert-based pre condition verification. Assertions
> // will be disabled once all programming errors are
> // corrected
>
> // assert-based class invariant verification
>
> // do the real business
>
> // assert-based class invariant verification
>
> // assert-based post-condition verification
> }

[ SNIP ]

Giovanni, I have some problems with the above examples. Let me explain
why.

Leaving temporarily aside the issue of "defensive" (I prefer to call it
"argument checking" in this case) code having errors, the main point I'd
like to make is that defensiveMethod() does not have pre-conditions that
could be addressed using asserts. It's *expected* that certain inputs
will come in that we then screen out, using that "if", and tell the
client that the input was unacceptable by throwing an
IllegalArgumentException. In this scenario, that code is *not* error
handling code (except in the widest sense, that of user input error
perhaps), and it's certainly not a programming error to be discovered
using assertions - it's business logic.

As far as the "defensive" code itself having errors, as far as I am
concerned go ahead and use assertions to help track those down if you
wish. You could have an assert related to the condition used by the "if"
if it made sense. I might add, if you're going to include stuff like
that in contrasting examples, it would have been only fair to have

assert (/* some egregiously wrong condition */);

The main point I'm making is, there are errors and then there are
errors. In the case of defensiveMethod() allowing for argument #2 to be
a String, really wanting it to be a "\\d+", but sometimes seeing "\\w+",
seeing a String that is not a "\\d+" is not a programming error. So why
would we ever consider using assertions?

AHS
 
Reply With Quote
 
Joshua Cranmer
Guest
Posts: n/a
 
      05-30-2009
Giovanni Azua wrote:
> The point I was defending was that Sun's commended way to use assertions was
> too categorical "Do not use assertions to check the parameters of a public
> method" [2]. The reasoning for my discrepancy towards that rule is that
> programs should not handle pre condition violations that are rooted in
> programming errors by means of exceptions e.g. IllegalArgumentException.


In the C and C++ world, such invalid parameters as null pointers can
cause what could have been merely an operation to fail to cause the
program to crash (the dreaded segfault). It is therefore very advisable
in those languages to always defend methods against invalid parameters,
even if it's programmer and not user error.

In Java, of course, the uncaught IllegalArgumentException would do much
the same thing that the analogous NullPointerException would have done.
There is, however, one key difference: if you check the arguments at the
beginning of the method, you prevent the class from entering an
erroneous, incomplete state, which allows for the ability to merely
consume the programmer error by simply invalidating the operation and
allowing recoverability.

> public void dbCMethod(...) {
> // assert-based pre condition verification. Assertions
> // will be disabled once all programming errors are
> // corrected


Given the history of software design, this should be interpreted as
assertions will never be disabled. How can you know when you've fixed
all programming errors? I'm willing to bet that even TeX still has
errors in it, and that's a program whose maintenance is purely bug-fix
these days.

> Defensive programming as defined by Bertrand Meyer above yields the
> following negative consequences in software engineering:
>
> - degrades performance


An intelligent design will only have to check the arguments once per
library level. Take a look at Java's Arrays' sort methods--instead of
performing the recursive call with the public, argument-checking
methods, all of the methods recursively call private, non-checking
methods. In the end, all public methods are defensive yet the penalizing
performance.

Also, if defensive checks are seriously degrading performance, you're
probably not doing them right.

> Once there is a programming error that lead to pre condition violations in
> production, it does not really matter what the preferred paradigm is, either
> DbC or Defensive Programming, the result will be either a crash or any
> behavior that differs to that stated in the software specification.


The worst that can happen if preconditions are violated and the callee
does not seek to adhere to any contract is that an exploit occurs--the
leak of information to those not permitted to see it. The wast that can
happen if the callee simply errors out immediately on violated
preconditions is that an error is promulgated upwards. Whatever results
come out of such a situation is entirely due to the unimaginative
programmer who assured himself that his program could not error.

> An excellent example on how the defensive programming approach i.e. check
> and throw exception can not only give a very subjective sense of safety but
> also become "the problem" is the 500 million loss case of Ariane 5 "The
> exception was due to a floating-point error: a conversion from a 64-bit
> integer to a 16-bit signed integer, which should only have been applied to a
> number less than 2^15, was erroneously applied to a greater number,
> representing the "horizontal bias" of the flight. There was no explicit
> exception handler to catch the exception, so it followed the usual fate of
> uncaught exceptions and crashed the entire software, hence the on-board
> computers, hence the mission. " [4]


This strikes me as a strong admission of support for checked exceptions,
not an argument against checking conditions. What if there hadn't been a
check, and the program had made the conversion as instructed? It seems
to me that there would have been a variable storing the horizontal bias
of the flight which was a few magnitudes of order off--which sounds like
it would have resulted in the craft thinking it was somewhere else,
ultimately crashing into an obstacle as a result of miscalculation.

This is also a result of underappreciation for Murphy's Law.


In the end, you have not convinced me of the harms of doing parameter
validation via exceptions versus asserts. I would much rather be told
that my method call failed via an exception, which permits me the
ability to handle it, than I would that it blithely continues into a
corrupt state.
--
Beware of bugs in the above code; I have only proved it correct, not
tried it. -- Donald E. Knuth
 
Reply With Quote
 
John B. Matthews
Guest
Posts: n/a
 
      05-30-2009
In article <gvrjm8$m4u$(E-Mail Removed)>,
Joshua Cranmer <(E-Mail Removed)> wrote:

> Giovanni Azua wrote:

[...]
> > An excellent example on how the defensive programming approach i.e.
> > check and throw exception can not only give a very subjective sense
> > of safety but also become "the problem" is the 500 million loss
> > case of Ariane 5 "The exception was due to a floating-point error:
> > a conversion from a 64-bit integer to a 16-bit signed integer,
> > which should only have been applied to a number less than 2^15, was
> > erroneously applied to a greater number, representing the
> > "horizontal bias" of the flight. There was no explicit exception
> > handler to catch the exception, so it followed the usual fate of
> > uncaught exceptions and crashed the entire software, hence the
> > on-board computers, hence the mission. "

>
> This strikes me as a strong admission of support for checked
> exceptions, not an argument against checking conditions.


This is precisely correct. The claims made in the work cited [1] are
subject to some debate [2]. The relevant exception was disabled in the
Ariane 4 inertial reference system (IRS) for performance reasons [3].
The IRS functioned correctly in Ariane 4 because the flight path
characteristics precluded an incorrect value [4-3.1o]. The Araine 4 IRS
was reused in the Araine 5 without adequate testing of the new flight
parameters and without re-enabling the exception [4-3.1r,s].

[...]

[1]<http://archive.eiffel.com/doc/manuals/technology/contract/ariane/page.html>
[2]<http://home.flash.net/~kennieg/ariane.html>
[3]<http://en.wikipedia.org/wiki/Ariane_5_Flight_501>
[4]<http://web.archive.org/web/20000815230639/www.esrin.esa.it/htdocs/tidc/Press/Press96/ariane5rep.html>
--
John B. Matthews
trashgod at gmail dot com
<http://sites.google.com/site/drjohnbmatthews>
 
Reply With Quote
 
Lew
Guest
Posts: n/a
 
      05-30-2009
John B. Matthews wrote:
> In article <gvrjm8$m4u$(E-Mail Removed)>,
> Joshua Cranmer <(E-Mail Removed)> wrote:
>
>> Giovanni Azua wrote:

> [...]
>>> An excellent example on how the defensive programming approach i.e.
>>> check and throw exception can not only give a very subjective sense
>>> of safety but also become "the problem" is the 500 million loss
>>> case of Ariane 5 "The exception was due to a floating-point error:
>>> a conversion from a 64-bit integer to a 16-bit signed integer,
>>> which should only have been applied to a number less than 2^15, was
>>> erroneously applied to a greater number, representing the
>>> "horizontal bias" of the flight. There was no explicit exception
>>> handler to catch the exception, so it followed the usual fate of
>>> uncaught exceptions and crashed the entire software, hence the
>>> on-board computers, hence the mission. "

>> This strikes me as a strong admission of support for checked
>> exceptions, not an argument against checking conditions.

>
> This is precisely correct. The claims made in the work cited [1] are
> subject to some debate [2]. The relevant exception was disabled in the
> Ariane 4 inertial reference system (IRS) for performance reasons [3].
> The IRS functioned correctly in Ariane 4 because the flight path
> characteristics precluded an incorrect value [4-3.1o]. The Araine 4 IRS
> was reused in the Araine 5 without adequate testing of the new flight
> parameters and without re-enabling the exception [4-3.1r,s].
>
> [...]
>
> [1]<http://archive.eiffel.com/doc/manuals/technology/contract/ariane/page.html>
> [2]<http://home.flash.net/~kennieg/ariane.html>
> [3]<http://en.wikipedia.org/wiki/Ariane_5_Flight_501>
> [4]<http://web.archive.org/web/20000815230639/www.esrin.esa.it/htdocs/tidc/Press/Press96/ariane5rep.html>


As the evidence mounts, the argument for "don't check input values" seems to
rest on "Bertrand Meyer says so", and the counterargument to "you cannot
prevent client code from handing in invalid values" is, "that's their
problem". If a check is done in client code to prevent bad values, that's the
same performance "penalty" as doing it in API code, but in the latter case the
code cannot fail to perform as contracted, and the check is centralized in the
logic that understands the preconditions.

So despite the disparaging tone implied in the use of the term "defensive
programming", the actual evidence and logic presented continue to support
putting condition checks in the API methods, and thus allowing the method to
deal sensibly with any given input, irrespective of error or mischief by
client code.

--
Lew
 
Reply With Quote
 
Stefan Ram
Guest
Posts: n/a
 
      05-30-2009
"Giovanni Azua" <(E-Mail Removed)> writes:
>- degrades performance


I have two thoughts on this.

1.) Assume »div(x,y)« had undefined behaviour when y == 0,
and we wanted to do this in an application:

for( x = 0; x < HUGE; ++x )div( x, y );

The application knows that in the case of y being 0, the
best thing to do is »f()«, so

if( y )for( x = 0; x < HUGE; ++x )div( x, y ); else f();

. We can see that it is sufficient to do the test /once
outside of the loop/ for a primitive variable »y« in a
single-threaded application. If the test would be done
inside of »div« instead, it would not be possible to move
it outside of the loop.

2.) Assume »div(x,y)« had undefined behaviour when y == 0.
One can always write a wrapper »defensiveDiv(x,y)« that has
defined behaviour for y == 0 and otherwise the same behavior
as »div(x,y)«, while it might be slower than »div(x,y)«.

On the other hand, given only »defensiveDiv(x,y)« it is not
possible to write a wrapper to get the behavior and run-time
properties of »div(x,y)«.

 
Reply With Quote
 
Giovanni Azua
Guest
Posts: n/a
 
      05-30-2009
Hallo Stefan,

"Stefan Ram" <(E-Mail Removed)-berlin.de> wrote in message
> I have two thoughts on this.
>
> 1.) Assume »div(x,y)« had undefined behaviour when y == 0,
> and we wanted to do this in an application:
>
> for( x = 0; x < HUGE; ++x )div( x, y );
>
> The application knows that in the case of y being 0, the
> best thing to do is »f()«, so
>
> if( y )for( x = 0; x < HUGE; ++x )div( x, y ); else f();
>
> . We can see that it is sufficient to do the test /once
> outside of the loop/ for a primitive variable »y« in a
> single-threaded application. If the test would be done
> inside of »div« instead, it would not be possible to move
> it outside of the loop.
>
> 2.) Assume »div(x,y)« had undefined behaviour when y == 0.
> One can always write a wrapper »defensiveDiv(x,y)« that has
> defined behaviour for y == 0 and otherwise the same behavior
> as »div(x,y)«, while it might be slower than »div(x,y)«.
>
> On the other hand, given only »defensiveDiv(x,y)« it is not
> possible to write a wrapper to get the behavior and run-time
> properties of »div(x,y)«.
>

Good insight indeed, very nice!

Gruss!
Giovanni



 
Reply With Quote
 
Lew
Guest
Posts: n/a
 
      05-30-2009
Stefan Ram wrote:
>> I have two thoughts on this.
>>
>> 1.) Assume �div(x,y)� had undefined behaviour when y == 0,
>> and we wanted to do this in an application:
>>
>> for( x = 0; x < HUGE; ++x )div( x, y );
>>
>> The application knows that in the case of y being 0, the
>> best thing to do is �f()�, so
>>
>> if( y )for( x = 0; x < HUGE; ++x )div( x, y ); else f();
>>
>> . We can see that it is sufficient to do the test /once
>> outside of the loop/ for a primitive variable �y� in a
>> single-threaded application. If the test would be done
>> inside of �div� instead, it would not be possible to move
>> it outside of the loop.
>>
>> 2.) Assume �div(x,y)� had undefined behaviour when y == 0.
>> One can always write a wrapper �defensiveDiv(x,y)� that has
>> defined behaviour for y == 0 and otherwise the same behavior
>> as �div(x,y)�, while it might be slower than �div(x,y)�.
>>
>> On the other hand, given only �defensiveDiv(x,y)� it is not
>> possible to write a wrapper to get the behavior and run-time
>> properties of �div(x,y)�.


Giovanni Azua wrote:
> Good insight indeed, very nice!


In Java, if the arguments are integers then division by 0 with the '/'
operator throws an 'ArithmeticException'. Is that "defensive programming"?
Does it make the '/' operation slow?

In Java, if the arguments are of a floating-point type, e.g., 'double', then
division by zero yields a double value ('NaN' or signed infinity). Is that
"defensive programming"? Does it make the '/' operation slow?

It seems that Java is able to define arithmetic '/' such that it can handle
all possible inputs without running into the performance problems that some
seem to think are a risk. If one wants to modify the behavior of division by
zero, say with integers to avoid causing an 'ArithmeticException', one can do
the optimized value check that Stefan suggests. Presumably this would be
inside a method that accepts a value for 'y' and forwards the action to 'f()'
or '/' as needed. Is that "defensive programming", or is the check outside
the loop for 'y == 0' and corresponding delegation to 'f()' just "good
programming"?

--
Lew
 
Reply With Quote
 
Robert Klemme
Guest
Posts: n/a
 
      05-31-2009
On 30.05.2009 12:46, Giovanni Azua wrote:
> Before moving into the concrete arguments I wanted to present the following
> definitions by Bertrand Meyer:
>
> Defensive programming: "A technique of fighting potential errors by making
> every module check for many possible consistency conditions, even if this
> causes redundancy of checks performed by clients and suppliers. Contradicts
> Design by Contract." [1, p1195]
>
> Design by Contract: "A method of software construction that designs the
> components of a system so that they will cooperate on the basis of precisely
> defined contracts. See also: defensive programming." [1, p1195]
>
> "Assertion Violation rule (1) A run-time assertion violation is the
> manifestation of a bug in the software." [1, p346]
>
> The key in the defensive programming definition is "check". It doesn't
> really matter what is done after encountering the problem either throwing
> exceptions or programming an alternate way e.g. Math.sqrt that handles the
> special case of negative input by returning Double.NaN. Please note that
> neither Eiffel "require" nor the Java "assert" for verification of pre
> conditions would fall under the category "check", by definition Design by
> Contract (DbC) is not a check, they are enabled only optionally and for
> discovering programming errors. Granted that Java assert feature is a small
> subset of what Eiffel DbC offers [3, p15 "So, is it like 'assert.h'"].
>
> The point I was defending was that Sun's commended way to use assertions was
> too categorical "Do not use assertions to check the parameters of a public
> method" [2]. The reasoning for my discrepancy towards that rule is that
> programs should not handle pre condition violations that are rooted in
> programming errors by means of exceptions e.g. IllegalArgumentException.
> However, the case of user input validation is a good use-case for using
> IllegalArgumentException.


Actually, if you write a library that is distributed as a jar the code
must check input into public accessible methods always and handle them
appropriately. This often means throwing an IllegalArgumentException
but it may also mean returning a special value such as NaN. Which
approach is more appropriate depends on the situation. But the code
needs to do this in order to maintain integrity of its internal state
(class invariants for example). Now, considering that a class is a
module much the same way as library every public method of it is part of
its API and marks the border between "outside" and "inside".

Basically this means that all public and protected methods need some
form of argument checking and dealing with illegal data. Other
languages have other means but since Java does not support DbC in the
language you have to use the features that you have.

IMHO you should only use assert for input checking if a) performance is
paramount _and_ b) you have _system_ test coverage that includes
combinations of all classes of correct and incorrect input data and all
possible invocation paths. This means that for most Java applications
out there (which do not play in the field of space mission control or
high performance realtime processing) you would rather have checks with
exceptions than using assert for input checking.

Personally I often use assert in situations where non trivial
calculations are done and I would have used a comment in pre Java 5.
The nice thing about assert is that you do not pay the performance
penalty in production while retaining a relatively short expression
which also helps documenting. For example

Collection<Foo> foos = ...
... complex processing here which must eventually empty foos ..
assert foos.isEmpty();

> In general, exceptions are meant to be handled
> programmatically. You can't nor should recover from programming errors but
> rather *fix* them e.g.


This is the precise reason why there are checked and unchecked
exceptions in Java. Similarly to Error and subclasses unchecked
exceptions should be handled programmatically only in relatively rare
cases, e.g. in a testing framework or in an application which must keep
running under all circumstances (e.g. a JEE container which must not
break just because a single application of potentially many deployed
applications runs berserk).

> A few excerpts from Bertrand Meyer's book:
>
> "Non-Redundancy principle: Under no circumstances shall the body of a
> routine ever test for the routine's precondition." [1, p343] For the example
> that depicts such case he writes "is not just unnecessary but unacceptable"
> [1, p343]


You need to keep on mind that this is in the context of his book where
he presents Eiffel. (Btw, it seems you got the quote numbering wrong,
this must be from OOSC which is [2] in your posting.) With a language
that provides rich DbC support and declarative pre- and postconditions
it is of course nonsense to check those inside method bodies.

> "Aside from performance considerations, however, the principal reason to
> distrust defensive programming is simply our goal of getting the best
> possible reliability. For a system of any significant size the individual
> quality of the various elements involved is not enough; what will count most
> is the guarantee that for every interaction between two elements there is an
> explicit roster of mutual obligations and benefits - the contract. Hence the
> Zen-style paradox of our conclusion: that to get more reliability the best
> policy is often to check less." [1, p345]


This still means that you need _some_ form of automatic checking of this
contract so you can detect violations. _How_ this checking is done is a
highly programming language dependent issue. In Eiffel you have DbC
support, in Java you have assert, checks and exceptions.

> "Lew" <(E-Mail Removed)> wrote
>> The method [Math.sqrt] must handle the illegal input. No amount
>> of concern for "performance" relieves it of responsibility to
>> handle a negative input.


> "Such a comment, however, comes from a microscopic understanding of
> reliability, focused on individual software elements such as the sqrt
> routine. If we restrict our view to the narrow world of sqrt, then the
> routine seems more robust with the extra test than without it. But the world
> of a system is not restricted to a routine; it contains a multitude of
> routines in a multitude of classes. To obtain reliable systems we must go
> from the microscopic view to a macroscopic view encompassing the entire
> architecture." [1, p344]


I can agree to that one although I find the statement very vague. And:
looking at the entire architecture does not make Lew's point invalid
that your microscopic checks need to be there - one way or another. You
cannot build a house on individual components that do not deliver
advertised quality.

> I hope all the excerpts and explanations illustrate my point.


Frankly, with all the quotes I am not sure what _your_ point really is.
You seem to advocate to drop what has been called "defensive
programming" in your article but since I did not follow the other thread
my insights into your own reasoning are limited.

Kind regards

robert

--
remember.guy do |as, often| as.you_can - without end
http://blog.rubybestpractices.com/
 
Reply With Quote
 
 
 
Reply

Thread Tools

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is On
HTML code is Off
Trackbacks are On
Pingbacks are On
Refbacks are Off


Similar Threads
Thread Thread Starter Forum Replies Last Post
To assert or not to assert... ImpalerCore C Programming 79 05-17-2010 12:47 PM
assert 0, "foo" vs. assert(0, "foo") Thomas Guettler Python 3 02-23-2005 07:53 PM
assert(x) and '#define ASSERT(x) assert(x)' Alex Vinokur C Programming 5 11-25-2004 08:48 PM
RE: remove assert statement (Was: Re: PEP new assert idiom) Robert Brewer Python 1 11-07-2004 06:53 PM
Use of do...while(0) in ASSERT macro Martin C Programming 40 11-27-2003 04:10 PM



Advertisments