From: H. S. Lahman on
Responding to Feathers...

> Funny thing about *final*. It looks like a great feature. You get to
> decide whether a class can have subclasses or whether a method can be
> overridden, but now I think it is too easy to abuse. Sure, if you have
> control over all of your code, you can make things *final* and remove
> *final* when it gets in the way, but if you develop code for someone
> else you can easily put them in a situation where it is hard or
> impossible to write unit tests for particular areas of code.

I don't see any need for it, at least for your examples. Whether one
needs subclasses now or in the future is dictated by problem space
abstraction. IOW, if you need generalization to solve the problem in
hand, then you need it. When the original developer uses 'final' to
prevent subclassing, that developer is just encoding his /opinion/ about
what changes in requirements the future will bring. He should keep his
opinions to himself.

Overriding concrete methods with inheritance is one of those things,
like FORTRAN assigned GOTOs, that seemed like a real good idea at the
time but turned out to a Really Bad Idea. IMO, overriding behaviors in
an inheritance tree is grounds for thumb-breaking.

However, I don't think 'final' is the problem here...

>
> Classic example:
>
> You have a class A from Vendor X and it has 15 methods. One of your
> classes, B, uses it and one of the methods that it uses has some
> sideffect you wouldn't like to see happen in a test. You'd like to mock
> out that method on A, and you could by subclassing A and overriding the
> method, but if Vendor X made A or that method of A final, your options
> are limited.

Alas, I have a problem with your basic premise about wanting to test the
side effect. I see three cases:

Case 1: The method in your B class is simply sending a message to A and
has no expectation about anything A does in response. That is, the B
method's specification does not depend on A even existing, much less
doing something specific. In that case one would normally stub the
entire A call and not worry about /any/ side effects.

case 2: The A method is a an accessor for knowledge that A owns that is
needed by B. Since that is just a knowledge access rather than a
behavior access, it is fair to stub the entire A method in the test
harness to return an appropriate value for the test case. [This case
isn't relevant here because side effects can only be produced by
behavior responsibilities, by definition.]

Case 3: The A method implements a behavior responsibility and the B
method depends upon what it does (e.g., it computes a value and returns
it for B to use). In that case cohesion, logical indivisibility, and
encapsulation are trashed and the specification of the B method includes
the specification of the A method because it is now an extension of the
B behavior. That is, the B method cannot be fully tested without a
correct implementation of the A method. Any stubbing in the test harness
is self-delusion because one is just testing the test harness. This
leads to two subcases:

Case 3A. the side effect is part of the fundamental specification of the
A behavior that the B method depends upon. In that case it is also part
of the B method's specification and must be tested so one can't stub it out.

Case 3B. the side effect is due to other behavior encapsulated in the A
method unrelated to the solution processing specified for the B method.
In that case the A method is poorly formed (low cohesion and not
logically indivisible) and you AND the application solution are screwed.

That side effect is now part of the B method specification whether one
wants it or not because any call to the B method will result in the side
effect when the production application runs. If that breaks the
application, you need to know it during testing so you can't stub it out
with a surrogate method that just has the desired behavior. And you
cannot be sure that the side effect does not break the application in
every possible context where the B method might be called until you test
it. IOW, stubbing would be equivalent to the test case redesigning the
application around how the developer /hopes/ the application will work
rather than how it actually works. That's just bad testing.

So in case 3 you either need to fix the A method's cohesion and logical
indivisibility or live with the side effect during the testing.


*************
There is nothing wrong with me that could
not be cured by a capful of Drano.

H. S. Lahman
hsl(a)pathfindermda.com
Pathfinder Solutions
http://www.pathfindermda.com
blog: http://pathfinderpeople.blogs.com/hslahman
"Model-Based Translation: The Next Step in Agile Development". Email
info(a)pathfindermda.com for your copy.
Pathfinder is hiring:
http://www.pathfindermda.com/about_us/careers_pos3.php.
(888)OOA-PATH



From: Thomas Gagne on
Declaring anything final is the ultimate expression of arrogance. No
programmer is omniscient. It is impossible to predict every conceivable
method or feature. To declare a class or method final is to declare its
perfection which humans are simply incapable of.

The two most popular reasons for declaring something final are both
shortsighted; performance and security. Recently Intel has announced
80-core chips with 1 thz (yes, 1000 ghz) performance. Unless your
programming for small systems hard-coding performance concessions is the
same kind of thinking that gave us the Y2K problem--to save two
bytes/date ignore the century. In the case of final, the concession is
the inability to ever subclass or override. Ever. Just because your
laptop is slow today doesn't mean your laptop will be slow tomorrow, or
that someone else's computer won't have sufficient CPU power today or
tomorrow. If using final for performance reasons were a categorical
syllogism it would be provably false.

Security at the class level seems irrational because the definition of a
class isn't changed when it's subclassed. What's being protected isn't
the class, but other methods whose behavior is unpredictable (brittle)
if passed anything other than an instance of the genuine article. If
such protections were really necessary than perhaps limiting parameters
to Strings and prohibiting subclasses or other classes implementing
Serializable, CharSequence, and Comparable would be the a more
appropriate, but still objectionable, alternative.

--
Visit <http://blogs.instreamfinancial.com/anything.php>
to read my rants on technology and the finance industry.
From: Michael Feathers on
H. S. Lahman wrote:
> Responding to Feathers...
>
>> Funny thing about *final*. It looks like a great feature. You get to
>> decide whether a class can have subclasses or whether a method can be
>> overridden, but now I think it is too easy to abuse. Sure, if you
>> have control over all of your code, you can make things *final* and
>> remove *final* when it gets in the way, but if you develop code for
>> someone else you can easily put them in a situation where it is hard
>> or impossible to write unit tests for particular areas of code.
>
>
> I don't see any need for it, at least for your examples. Whether one
> needs subclasses now or in the future is dictated by problem space
> abstraction. IOW, if you need generalization to solve the problem in
> hand, then you need it. When the original developer uses 'final' to
> prevent subclassing, that developer is just encoding his /opinion/ about
> what changes in requirements the future will bring. He should keep his
> opinions to himself.
>
> Overriding concrete methods with inheritance is one of those things,
> like FORTRAN assigned GOTOs, that seemed like a real good idea at the
> time but turned out to a Really Bad Idea. IMO, overriding behaviors in
> an inheritance tree is grounds for thumb-breaking.
>
> However, I don't think 'final' is the problem here...
>
>>
>> Classic example:
>>
>> You have a class A from Vendor X and it has 15 methods. One of your
>> classes, B, uses it and one of the methods that it uses has some
>> sideffect you wouldn't like to see happen in a test. You'd like to
>> mock out that method on A, and you could by subclassing A and
>> overriding the method, but if Vendor X made A or that method of A
>> final, your options are limited.
>
>
> Alas, I have a problem with your basic premise about wanting to test the
> side effect. I see three cases:
>
> Case 1: The method in your B class is simply sending a message to A and
> has no expectation about anything A does in response. That is, the B
> method's specification does not depend on A even existing, much less
> doing something specific. In that case one would normally stub the
> entire A call and not worry about /any/ side effects.

That's really what I intended. The typical way to stub a method that
comes from another library is to subclass and override that method. If
the method or the class is final, you're stuck. All you can do is
create some wrapper for the class and use the wrapper rather than have a
direct dependency.

Michael Feathers
www.objectmentor.com
michaelfeathers.typepad.com
author of: Working Effectively with Legacy Code (Prentice Hall 2005)
From: Michael Feathers on
Thomas Gagne wrote:
> Security at the class level seems irrational because the definition of a
> class isn't changed when it's subclassed. What's being protected isn't
> the class, but other methods whose behavior is unpredictable (brittle)
> if passed anything other than an instance of the genuine article. If
> such protections were really necessary than perhaps limiting parameters
> to Strings and prohibiting subclasses or other classes implementing
> Serializable, CharSequence, and Comparable would be the a more
> appropriate, but still objectionable, alternative.

True. The sad thing about it is that it doesn't really protect
anything. Teams that run into trouble with final in vendor code often
wrap APIs. Well, if you wrap the API to be able to mock it for test,
you've put in a seam that can be used to replace something maliciously also.

It's kind of sad to consider that maybe we can have secure software but
only if we can't be sure that it works :-)

Michael Feathers
www.objectmentor.com
michaelfeathers.typepad.com
author of: Working Effectively with Legacy Code (Prentice Hall 2005)
From: Michael Feathers on

Jerry Coffin wrote:
> In article <puDCh.148$PL.26(a)newsread4.news.pas.earthlink.net>,
> mfeathers(a)objectmentor.com says...
>
>>Funny thing about *final*. It looks like a great feature. You get to
>>decide whether a class can have subclasses or whether a method can be
>>overridden, but now I think it is too easy to abuse. Sure, if you have
>>control over all of your code, you can make things *final* and remove
>>*final* when it gets in the way, but if you develop code for someone
>>else you can easily put them in a situation where it is hard or
>>impossible to write unit tests for particular areas of code.
>
>
> [ ... ]
>
> Java's final strikes me as an example of second-system effect.
> Especially early on, C++ really could have used final or something very
> similar. In fact, upon close analysis Scott Meyers once stated (mostly
> correctly, IMO) that in a C++ hierarchy, classes should divide into two
> groups, with no overlap: abstract classes that can't be instantiated,
> and leaf classes from which no further deriviation is allowed. FWIW, he
> originally wrote about this in the July/August 1994 issue of The C++
> Report. Doing a bit of looking, he also posted a bit about it on Usenet
> around the same time:
>
> http://groups.google.com/group/comp.lang.c++/msg/dc1a601560ba8dcf
>
> Had it been available in early C++, a final keyword probably would have
> been quite useful. In fact, I would tend to agree with Scott Meyers that
> most (perhaps all) concrete classes should have been treated as final.
> This problem hasn't entirely disappeared from C++, but large hierarchies
> mostly have, so its utility would now be much more limited (at most).
>
> Java eliminated most (if not all) of the reasons final would have been a
> good thing in C++, then included final anyway. In Java, final is
> associated with problems far more than solutions.

I tend to be of two minds about that sort of thing. On the one hand,
it's great to give developers guidance, but unless you can completely
anticipate how they are going to work in the future, those sorts of
resrictions can be very problematic. For instance, the problem I
outlined only began to be noticed as more people started to get serious
about unit testing.


Michael Feathers
www.objectmentor.com
michaelfeathers.typepad.com
author of: Working Effectively with Legacy Code (Prentice Hall 2005)