Re: Ensuring a method is overridden
Daniel Pitts wrote:
Assertions are another way of catching bugs in production. If your
assertions are causing a large performance penalty, then you can
consider disabling them in production, or adjusting them to make more
sense. Otherwise, leaving them in and on is considered a best practice.
Robert Klemme wrote:
Well, by you apparently. I would not claim this is a general best
practice in the Java world. If I consider checks that important that I
don't want to switch them off, then I wouldn't place them after an
"assert" - I'd just do them all the time.
This rather misses the point of assertions also. It isn't about whether
checks should or should not always happen. It's about where the algorithmic
invariants are, and which ones are important to check, and when.
It is a subtle point and one that takes some getting used to, I conclude based
on what I hear from various Java programmers. Admittedly, Java's 'assert' is
rather more powerful than mere invariant checking, but that is the fundamental
viewpoint and the springboard from which one should approach assertions.
Invariants are like the checkpoints in the Tour de France. When you reach
one, and prove that you got there correctly, it means you have successfully
completed that leg of the algorithmic journey.
Daniel Pitts wrote:
You don't need to test for all invariants everywhere, especially
invariants that would cause an exception anyway (such as a collection
must only contain objects of a certain class. That will be caught by a
ClassCastException, which is a built-in assertion you can not disable)
What a major misstatement about assertions! The proper way to use 'assert' in
this scenario would be something like:
assert foo instanceof DesiredType;
just after the block that would have thrown the CCE. The invariant here is
that 'foo' is an instance of the desired type, which the exception enforced
and the 'assert' statement proves. Assertions work *with* exceptions, not
*instead of* them.
This ties right in with what Robert Klemme wrote:
Sometimes it is crucial to determine the point in time when an error
occurs in order to help in debugging. Your ClassCastException (not
assertion!) might show up at a point where it is not clear any more when
that illegal object made it into the collection. If a class is complex
then it can be reasonable to include an invariant check via assert in
every method that changes state (or even in _every_ method in certain
cases, e.g. when state of referenced objects can be changed outside the
class).
To use the CCE example, putting the assert right after the point that checks
the type is a run-time way to isolate the potential point of failure, and to
guarantee that no CCE will occur further down the algorithmic road.
Minor detail with this specific example: with generics many CCEs are avoided
at compile time, so the risk of ClassCastExceptions would be nil. We should
always prefer compile-time safety to run-time safety. One could still use an
'assert' just to document and prove the invariant even so.
--
Lew