Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
374 views
in Technique[技术] by (71.8m points)

language agnostic - Some (anti-)patterns on using assert (Java, and others)

Finally, I have a question to ask on Stack Overflow! :-)

The main target is for Java but I believe it is mostly language agnostic: if you don't have native assert, you can always simulate it.

I work for a company selling a suite of softwares written in Java. The code is old, dating back to Java 1.3 at least, and at some places, it shows... That's a large code base, some 2 millions of lines, so we can't refactor it all at once.
Recently, we switched the latest versions from Java 1.4 syntax and JVM to Java 1.6, making conservative use of some new features like assert (we used to use a DEBUG.ASSERT macro -- I know assert has been introduced in 1.4 but we didn't used it before), generics (only typed collections), foreach loop, enums, etc.

I am still a bit green about the use of assert, although I have read a couple of articles on the topic. Yet, some usages I see leave me perplex, hurting my common sense... ^_^ So I thought I should ask some questions, to see if I am right to want to correct stuff, or if it goes against common practices. I am wordy, so I bolded the questions, for those liking to skim stuff.

For reference, I have searched assert java in SO and found some interesting threads, but apparently no exact duplicate.

First, main issue, which triggered my question today:

SubDocument aSubDoc = documents.GetAt( i );
assert( aSubDoc != null );
if ( aSubDoc.GetType() == GIS_DOC )
{
   continue;
}
assert( aSubDoc.GetDoc() != null );
ContentsInfo ci = (ContentsInfo) aSubDoc.GetDoc();

(Yes, we use MS' C/C++ style/code conventions. And I even like it (coming from same background)! So sue us.)
First, the assert() form comes from conversion of DEBUG.ASSERT() calls. I dislike the extra parentheses, since assert is a language construct, not (no longer, here) a function call. I dislike also return (foo); :-)
Next, the asserts don't test here for invariants, they are rather used as guards against bad values. But as I understand it, they are useless here: the assert will throw an exception, not even documented with a companion string, and only if assertions are enabled. So if we have -ea option, we just have an assertion thrown instead of the regular NullPointerException one. That doesn't look like a paramount advantage, since we catch unchecked exceptions at highest level anyway.
Am I right supposing we can get rid of them and live with that (ie. let Java raise such unckecked exception)? (or, of course, test against null value if likely, which is done in other places).

Side note: should I have to assert in the above snippet, I would do that against ci value, not against the getter: even if most getters are optimized/inlined, we cannot be sure, so we should avoid calling it twice.

Somebody told, in the last referenced thread, that public methods should use tests against values of parameters (usage of the public API) and private methods should rely on asserts instead. Good advice.
Now, both kinds of methods must check another source of data: external input. Ie. data coming from user, from a database, from some file or from the network, for example.
In our code, I see asserts against these values. I always change these to real test, so they act even with assertions disabled: these are not invariants and must be properly handled.
I see only one possible exception, where input is supposed constant, for example a database table filled with constants used in relations: program would break if this table is changed but corresponding code wasn't updated.
Do you see other exceptions?

Another relatively frequent use I see, which seems OK: in the default of a switch, or at the end of a series of else if testing all possible values (these cases date back before our use of enums!), there is often an assert false : "Unexpected value for stuff: " + stuff;
Looks legitimate for me (these cases shouldn't happen in production), what do you think? (beyond the "no switch, use OO" advices which are irrelevant here).

And finally, are there any other useful use cases or annoying gotchas I missed here? (probably!)

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

The number one rule is to avoid side-effects in assertions. In other words, the code should behave identically with assertions turned off as it does when assertions are turned on and not failing (obviously assertions that fail are going to alter the behaviour because they will raise an error).

The number two rule is not to use assertions for essential checks. They can be turned off (or, more correctly, not turned on). For parameter-checking of non-private methods use IllegalArgumentException.

Assertions are executable assumptions. I use assertions to state my beliefs about the current state of the program. For example, things like "I assume that n is positive here", or "I assume that the list has precisely one element here".


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...