Java deficiencies: "final" and "private"

9 views
Skip to first unread message

Tom

unread,
Oct 8, 2009, 3:58:16 AM10/8/09
to Noop
This post is just to point out a feature which I dislike in Java, that
I hope won't get inherited by noop.

NOTE: I'm talking here about "final" in the sense of declaring classes
and methods non-overridable, not "final" in the sense of reference
immutability; the latter has its own problems which have already been
much discussed here.

A common problem in extending a third-party library is that the
creators of the library didn't anticipate the ways you might want to
use their software. There's "API", which is how they *intend* for you
to use it, but they inevitably haven't provided you with all the
customizability you wanted. So the obvious solution is for you to
subclass their class and make the changes you need. This works well
enough in Java as long as they haven't declared their classes or
methods final, or declared their variables package or private. Once
this happens (and it happens a lot) you quickly find yourself writing
a lot of reflection code and, once that fails (as it inevitably does),
copy-and-pasting large chunks of code in order to get the
customization you need.

Am I suggesting we get rid of these constructs? Not at all (at least
not all of them)! "private" is very useful as a way of denoting a
property which is not part of API, and is subject to change. I don't
think it's reasonable to ask the creators of 3rd party libraries to
declare everything "protected" just so I have the ability to modify
it; private has a purpose! It means: "don't depend on this; it may
change in the future".

But guess what? Because right now I'm forced to use Java reflection to
set a private variable, I now no longer benefit from compile-time
checking. The compiler and I both know that class "Foo" has a private
variable named "bar", but I'm not allowed to write Java code directly
referencing it. Instead I have to reference it via a String, using
reflection. What's wrong with that picture? Well now when the third
party code changes, instead of getting a compile-time error, I have to
wait for a runtime exception to get thrown to find out that things are
not as my code assumes them to be. That's just crappy, crappy, crappy.

The bottom line is that 3rd party developers should be allowed to make
things private, which means they are declaring that it is not part of
API, and meanwhile I should be allowed to accept the risk that it will
change in a future version and access it anyway. It should be a
warning, in other words, which I can choose to ignore or suppress.

Final in the class and method sense should similarly be an expression
of intent by the makers of the class, which subclassers can willfully
disregard if they need to.

Package visibility is useless and should go away.

Tom

Thierry

unread,
Oct 9, 2009, 2:37:12 AM10/9/09
to no...@googlegroups.com
I can not agree on that : I think that the "final" keyword is one of the most important and the most usefull keyword in Java. The scenario you described is, actually, exactly what "final" was created for.

The "final" keyword is used to lock an algorythme.

Example :

public class abstract AbstractFoo {
  public final void myFinalMethod() {
    foo1(); // open the banana
    foo2(); // eat the banana
    foo3(); // throw the skin
  }
 
  protected abstract void foo1();
  protected abstract void foo2();
  protected abstract void foo3();
}

public class SimpleFoo extends AbstractFoo()  {
  // Here can not rewrite myFinalMethod() but have to write
  // foo1,2,3 methods
}

The process is still open but the ordering logic is closed ! Here you can't eat the banana before it was opened (some people do, well, humm)... This is GOOD !

Thierry Leriche-Dessirier
Ingénieur Architecte Web JEE



2009/10/8 Tom <pel...@gmail.com>

Michael Feathers

unread,
Oct 9, 2009, 3:11:10 AM10/9/09
to no...@googlegroups.com
I have this rant that I do on final. My opinion is that final is an
attempt to address a social problem with a technical solution. You
can do it, but the price is pretty high. I like the "soft final"
approach that the Eclipse API Rules of Engagement mentions. It's also
fair to note that many languages do just fine without having anything
like final.

Michael

t0rx

unread,
Oct 9, 2009, 3:54:02 AM10/9/09
to no...@googlegroups.com
So Michael, you're trying to solve a social problem (people use final
too much) with a technical one (don't have final)?

More seriously, not having the ability to close off implementation
generates a problem for people producing commercial libraries. If
someone finds a problem and it's due to them abusing your
implementation then their first port of call will usually be your
support channel. This in turn results in an increasing "I won't help
you until you spend a huge amount of time proving it wasn't you"
attitude back to users which doesn't help anyone.

Cleanly defining and separating how you allow people to extend your
library is an essential tool. I agree that people cam be
overcautious, but removing the feature altogether seems wrong.

Yan

On 9 Oct 2009, at 08:11, Michael Feathers <michael....@gmail.com>
wrote:

Michael Feathers

unread,
Oct 9, 2009, 4:21:05 AM10/9/09
to no...@googlegroups.com
Yet, there are languages with nothing like final which do very well.
I think it's a cultural thing. As well, the Eclipse API is used by
commercial users. In a commercial library situation (and it seems
that there are less and less of those these days) the important thing
is getting the ground rules in place.

When you buy a stereo there's a notice that opening it up voids the
warranty, but it's screwed shut rather than welded. Final is more
like a weld in my experience.

Just something to think about. If a language built in support for
getting past final in tests which was extremely easy, I think that
would work too.

Michael

t0rx

unread,
Oct 9, 2009, 4:54:19 AM10/9/09
to no...@googlegroups.com, no...@googlegroups.com
Or (thinking some more) do we need final at all if we have private
(which would be accessible in tests)? If you need to lock down
implementation then delegate to a private method - this gives an "all
or nothing" approach which may be a reasonable compromise. But it
feels a bit clunky.

Yan

On 9 Oct 2009, at 09:21, Michael Feathers <michael....@gmail.com>
wrote:

Ben Rady

unread,
Oct 9, 2009, 8:41:30 AM10/9/09
to no...@googlegroups.com
Why do we need to copy Java's final behavior wholesale? If the goal is to provide protection to API developers, I think we can do better than Java's final keyword (as used on classes and methods, anyway).

Ben

Michael Feathers

unread,
Oct 9, 2009, 8:43:35 AM10/9/09
to no...@googlegroups.com
I think it's interesting to note as well that it is a feature that can
always be added later.

Christian Gruber

unread,
Oct 9, 2009, 9:27:13 AM10/9/09
to no...@googlegroups.com
I'm wondering how relevant final classes and methods even are, semantically, if we don't have implementation inheritance at all.  What would the meaning of such a semantic be in the context of our strong-delegation concept (inheriting contract from dependencies marked as "delegates")

As an aside, the "package friendly" visibility was mentioned - I don't know how I feel about that.  On one hand, I like the ability to have my method implementations really public for testing, but private to the world.  However, I think this is less valuable if we implement a combination of proposals on the table.  If, for example, we implement "no variable declarations can be concrete types, except in test-scoped code" then in effect all non-interface-overriding methods are private from production code, but open in testing code.  Also, with some of the patterns of use from dependency-injection and things like strong delegation, I suspect people's code will be much more decoupled, which means you'll need less cross talk between classes anyway, so one should be in a better position to be able to test without package-friendly methods anyway.

On the other hand, I keep wondering about having a stronger component concept - a clear grouping of classes that explicitly mean a component with an interface (or interfaces) and a back-end, with everything within the component being more accessible internally, but invisible to the outside world.  I've occasionally wished that packages had a stronger semantic like that, but the above rule of "no concrete type declarations in non-test code" might effectively create those conditions.  Or perhaps a softening - one can only declare variables as a concrete type if such is in your package (though, if we implement against a jvm back-end, I think we would end up with a hole a mile wide, since I can arbitrarily declare code in your package, and load it later).  

All of this is tough, because we have to find the balance between keeping the code maintainable, and treating the developer like an invalid.  I want to not hamper the expert from developing kick-ass software, but constrain the beginner so he can't create too horrible a mess.

cheers,
Christian.
--
-----
Christian Gruber
christiane...@gmail.com
Reply all
Reply to author
Forward
0 new messages