Your three counter-arguments boil down to:

1. Don't expect your team to be stupid/make mistakes.
2. Don't be stupid/make mistakes.
3. Don't write stupid/mistaken code.

I think we can all agree those are good points.  The question is cost vs. 
benefit of defending 
against points where these break down.  I find the cost of 
automatically-inserted "final" to be 
minimal (bordering on zero given an IDE), and the benefit to be 
non-minimal/non-zero, and therefore 
I go with it.

Let's take a particular case and break it down to see how "final" works out in 
the end.  Note that 
parameter-processing methods like:

String myConcat(String left, String right) {
   if ( left == null ) left = "";
   if ( right == null ) right = "";
   return left + right;
}

...can be just as well written as:

String myConcat(final String left, final String right) {
   if ( left == null ) return myConcat("", right);
   if ( right == null ) return myConcat(left, "");
   return left + right;
}

This rewrite gives you a couple solid advantages.  First, it's more expressive 
of intent (although 
that might be my functional programming-tinted eyes).  To see the second 
advantage, consider this code:

String myConcat(String left, String right) {
   if ( left == null ) left = "";
   if ( right == null ) left = "";
   return left + right;
}

Did you notice the bug?

The result of the buggy "myConcat" will be an erroneous String consisting of 
the characters 'n', 
'u', 'l', 'l'.  This will be kicking around and might well not cause an 
explosion until some far 
away point (probably after you've stored it in your database a bunch of times 
for posterity).  The 
corresponding error symptom in the "final" case will be an infinite recursion 
at the spot where the 
error occurred, so the StackOverflowError will nicely point you right to where 
the bug is, and you 
won't have a chance to do something bad with the erroneous value.  I consider 
that a pretty huge win.

Now, a misguided and performance-obsessed developer might freak out because you 
*may* have a couple 
extra method calls and branches in there, but the reality is that the HotSpot 
compiler will take 
care of those cases in short order.  Plus you're setting yourself up for 
success when you reach a 
JVM version which optimizes recursive tail calls.

This case demonstrates well my general experience with "final": it consistently 
leads me to more 
expressive and less buggy code.  Removing "final" is usually a sign that I'm 
trying to pull a stunt 
that's going to get me into trouble, and often a sign of premature 
optimization.  Given that 
experience, I'm really a fan.

More reasons I like "final" over on my blog: 
http://enfranchisedmind.com/blog/2007/12/16/some-final-patterns/

Also, check out a before and after of my functional-y Java at:
http://enfranchisedmind.com/blog/2005/12/16/this-is-your-brain-this-is-your-brain-on-ocaml/

(Now, what's *really* interesting is that I don't use "final" in Groovy, and I 
wouldn't even if it 
actually worked exactly like Java's "final".  There's a different sensibility 
in Groovy than in 
Java.  Which is also why I use an IDE to write Java, but write Groovy in vi.)

~~ Robert Fischer.
Grails Training        http://GroovyMag.com/training
Smokejumper Consulting http://SmokejumperIT.com
Enfranchised Mind Blog http://EnfranchisedMind.com/blog

Check out my book, "Grails Persistence with GORM and GSQL"!
http://www.smokejumperit.com/redirect.html


Reinier Zwitserloot wrote:
> This is a spin-off from the 'code reviews' thread (http://
> groups.google.com/group/javaposse/browse_thread/thread/
> 827d3257c903e9bd/35db9fd36906dd5d#35db9fd36906dd5d )
> 
> Robert Fischer isn't the first soul I've heard mention that they
> either enforce setting all parameters to 'final', or, because that
> created ginormous method signatures, configure their IDE to warn/error
> when parameters are modified.
> 
> I wonder if this really is a good idea.
> 
> The usual arguments come in three flavours, at least as far as I've
> heard them:
> 
> 1. The confusion argument: java is strictly pass-by-value so
> someParameter = x; does NOT change the meaning of 'someParameter' in
> the code that called your method. By disallowing assignment you avoid
> the confusion (This is Robert's argument).
> 
> 2. The overlook argument: As methods grow larger (or even if they
> remain small and you're just glancing) you may miss a re-assignment to
> a parameter, and as you add some code onto the end of a method, for
> example to fix a bug, you erroneously think the value has been
> untouched. Proponents of this argument also usually enforce that
> 'return' must be the last statement, under the presumption that a mid-
> method return may let people think that the code they just added to
> the end is always run before the method returns normally.
> 
> 3. The save-the-value argument: You never know when you need to
> original value that was passed in, so changing it may require
> refactors down the line.
> 
> 
> 
> They all seem like bullpucky to me though. Point-by-point
> deconstruction:
> 
> 1. If you're going to make rules because your fellow programmers don't
> know their arse from their teakettles, you'll never get anything done.
> Sure, for extremely obscure stuff I can see some value in setting up
> style checkers and the like to disallow certain operations, but
> something as simple as pass-by-value? Also, even if you really do have
> such mythically stupid programmers, you can still catch them in their
> error: Anybody that changes any local variable or parameter and then
> never touches it again is clearly doing SOMETHING wrong (that
> assignment was a no-op!), and if someone makes the mistake of thinking
> that java is pass-by-reference, they'll hit that sooner rather than
> later. javac doesn't check for this, but findbugs does. In fact, I
> think that most methods that would only work if java is pass-by-ref
> will make this mistake.
> 
> 2. You can't just shove code into a method without understanding the
> method first. For example, I've seen lots of methods that take their
> incoming parameter, and then perform a normalization on it; for
> example, an incoming string gets a if ( x == null ) x = ""; treatment
> so future code can treat null and the empty string the same. Any
> casual method editor probably THINKS they are working on the
> normalized version. By enforcing the original coder to come up with a
> second variable to hold the normalized version, you're actually
> creating the very situation you tried to avoid!
> 
> 3. ... then why don't you refactor it? We have refactor tools for a
> reason.
> 
> 
> 
> I have a soft (meaning: feel free to break it if you have a decent
> reason to do so) rule regarding changing your method parameters:
> 
> Make all changes to all parameters before the real meat of the method
> begins. Then, consider them final. (In other words, if you want to
> replace a parameter being 'null' with a default, or expand an input
> with a prefix, or any other normalization, do so at the very top of
> the method, then never change it again).
> 
> Unfortunately there's no tool out there that has a rule to check if
> you adhere to it.
> 
> 
> > 
> 



--~--~---------~--~----~------------~-------~--~----~
You received this message because you are subscribed to the Google Groups "The 
Java Posse" group.
To post to this group, send email to [email protected]
To unsubscribe from this group, send email to 
[email protected]
For more options, visit this group at 
http://groups.google.com/group/javaposse?hl=en
-~----------~----~----~----~------~----~------~--~---

Reply via email to