We're very much in agreement, on all points you just made.
I won't speak for anyone else, the argument I was making was for
verbosity in support of defensive programming. I see Java code all the
time where exceptions are try-caught with no thought placed into
handling the problem somewhere - defensive coding fail...and handling it
properly would add verbosity.
I see main methods all the time where someone assumes the number and
type of arguments. Defensive coding fail. I see methods all the time -
like I said - where the same coder wrote the calling code and called
code, and makes assumptions about what the calling code will do.
Defensive coding fail.
Or they make the naive assumption that people read Javadocs thoroughly.
It's not the calling code's responsibility to protect the called code,
after all. Given that we have to consider the bounds of parameters
carefully, I don't see how some verbosity in the form of defensive code
is objectionable.
"Here be dragons" often means simply that there is - that we have to
guard against what the calling code is doing.
I see. Thanks for clarifying.
It looks like I had not understood the discussion about verbosity in the
same sense as you do. In my view, when talking about verbosity, we talk
about a measure on, and that's the important point, an iso-functional
basis. To illustrate, when I switch on a "verbose" flag on my command
line, I do not expect the command to perform any differently than before
-- only that it should be more talkative about it. But the functions it
performs should not be impacted by it.
To illustrate with code, and to pick some of the original examples
again, take the following two methods:
boolean method1( String input ){
return "yes".equals( input );
}
boolean method2( String input ){
final boolean ret;
if( input == null ){
ret = false;
}
else if( input.equals("yes") ){
ret = true;
}
else {
ret = false;
}
return ret;
}
This is what I mean. Both methods perform exactly the same for any
input. The only matter in which they differ is their verbosity.
And to pick up the argument again: it could be argued that the latter
form is preferable, because it is more obvious what happens in each
case. I argue against that. Not generally, but in this case. Because
what's going on there is a very basic operation (making sure the input
is exactly the String "yes"). The second form is too verbose -- that is,
so verbose that it becomes clutter. The first (non-verbose) form
expresses the intent clearly enough. If there is a "programmer" who does
not understand that (especially the null-implication), then I'm sure Lew
would have some poignant recommendations as to what avenues of
employment they rather ought to pursue, and I would happen to be in
agreement with him.
Some of what you are talking about, on the topic of defensive
programming, on the other hand, I would call functional defects. I do
not perceive those as being matters of verbosity or not, but of whether
the code is functionally complete or not. To your hypothetical
programmer who does not handle exceptions because it would supposedly
add verbosity, "verbosity" is but a pathetic front to mask either their
lack of professionalism.
The other examples you give definitely fall in the realm of defensive
programming. Yes, a method should not make hidden assumptions as to its
parameters (OTOH there would be nothing wrong per se with what I'd call
an explicit assumption along the lines of: if( argumentNotValid ) throw
new IllegalArgumentException(); ). Yes, every caller should be defensive
about what the callee might return (within the boundaries of its
contract). It should be noted that annotations have given us a potential
tool forcibly to impose more stringency in these regards, although the
way I see it it won't really be usable until teh Oracle makes the effort
to formalise them and adds them to the core lib (I mean things like
@NotNull). It still needs to mature a bit I think.
The aforementioned is mitigated in code that is internal to a component
(in the spirit of encapsulation, code ought to be divided into
components such that the density of interrelation of code within a
component is always strictly greater than that of interrelation of code
in different components). Think private or package-private methods. It
is often impractical and counter-productive to have
to forego any hidden assumptions in those parts of the code. Then again,
it is precisely the combination of these two aspects, that it is
impractical and that it would be necessary, which makes OO and esp.
encapsulation such a virtuous tool: by structuring code and data flow,
you *can* relegate, notably, input checks to the boundaries of the
component and operate on assumptions within the component. (Granted,
this does not help the case where multiple programmers who are not in
relation with each other work on the internals of the same component,
which is why such a situation should be avoided).