The Source for Java Technology Collaboration
User: Password:



Felipe Leme

Felipe Leme's Blog

Final? Not yet...

Posted by felipeal on February 13, 2007 at 08:11 AM | Comments (8)

Now that the pandora box is open is open, it is my turn to suggest a (possible worthless, I know) change to the Java language: the semifinal modifier!

I had this idea on my way home last week, after teaching the final keyword for my current Globalcode class. The idea was basically this: final is a well designed modifier, as it has a similar meaning on the many places it can be used (variable, method and class definitions). So wouldn't it be nice if there was a similar modifier for definitions that are not quite final?

Enters the semifinal modifier - too bad I didn't have this idea during the World Cup :-(.

The first and most useful case (if not the *only* useful case at all) is when defining a class: a class (or interface) marked as semifinal can be extended, but its public behavior cannot change. In other words, you can override any method of this class (as long as you do not make then more accessible than the original), but you cannot add any public method (or attribute).

The reasoning? I think such classes could be useful when defining APIs, frameworks, or components, where you do not want to allow extended classes to be more capable than its superclass (a side effect of this new class modifier is that the compiler could generate warnings when a subclass of a semifinal class is used as the type of a reference, parameter or method return). For instance, say you have an interface I that has methods mA() and mB(), and one implementation X that adds a method mC(). Over time, mC() becomes so popular and necessary that the clients of I always cast it to X, in order to call mC(). Well, if this method is so necessary, it should be part of I, and not an implementation detail - declaring I as semifinal would force it (i.e., X could not add a new public method mC()).
Here is an example:
semifinal class SuperClass {
   protected void m1() { 
   }
   protected void m2() { 
   }
   public void m3() {
   }
}

class SubClass extends SuperClass { 

   // declaration below is valid: same access level (protected)
   protected void m1() { 
   }

   // declaration below is not valid: more accessible (public)
   public void m2() { 
   }

   // declaration below is valid: overriding public method
   public void m3() { 
   }

   // declaration below is valid: new method, but private
   private void myMethod() { 
   }

   // declaration below is not valid: new public method
   public void myExtendedMethod() { 
   }
} 
To be honest, I never designed a long-lasting API, so I am not sure it makes sense at all - but if you make an analogy to Java EE specification and vendor-specific features, it might...

Now, if this new modifier is as orthogonal as final, it could be applied to variables and methods as well. In the case of a variable, it means its value must be defined at least once, and at most twice (and not exactly once, as it happens with final). I can see at least two situations where this is helpful:

1.When there is an optional assignment for an nonexistent value . Example:

semifinal MyObject o = getMyObject();
if ( o == null ) {
  o = new MyObject();
}
// from this point on, o is final and cannot be changed
Without semifinal, you have to either create a temporary reference:

final MyObject tmpObject = getMyObject(); // dirty hack
final MyObject o = tmpObject != null ? tmpObject : new MyObject();
Or not use final at all:

MyObject o = getMyObject();
if ( o == null ) {
  o = new MyObject();
}
// o can be changed, as it is not final
2.Before try/catch blocks:

semifinal MyObject o = null;
try {
   o = getMyObject(); // getMyObject() throws NastyException, which is checked
   // from this point on, o is final and cannot be changed
} catch( NastyException e ) {
  throw new NastyRuntimeException( "o is a nasty reference. No dessert for it!", e ); 
}
// we must use o from this point on, but it should not be changed
Again, without semifinal, we have to use the dirty hack or not use final at all:

MyObject tmpObject = null;
try {
   tmpObject = getMyObject(); // getMyObject() throws NastyException, which is checked
   // from this point on, o is final and cannot be changed
} catch( NastyException e ) {
  throw new NastyRuntimeException( "o is a nasty reference. No dessert for it!", e ); 
}
final MyObject o = tmpObject;
or

MyObject o = null;
try {
   o = getMyObject(); // getMyObject() throws NastyException, which is checked
   // from this point on, o is final and cannot be changed
} catch( NastyException e ) {
  throw new NastyRuntimeException( "o is a nasty reference. No desert for it!", e ); 
}
// we must use o from this point on, but it can be changed as it is not final

The final (no pun intended) case is the method definition: a semifinal method means it can be overriden, but at most by the direct subclass (i.e., it cannot be overriden more than once). To be honest, that's the less useful of the three situations (I mean, assuming the other two are any useful at all :-), but it would allow some interesting (not to say weird) possibilities, like this:

protected abstract semifinal void doIt();
Such definition means the method doIt() must be overridden by the subclass (as it is abstract), but is final after that (i.e., it cannot be overridden by a subclass of the subclass). It *might* be useful when implementing the Template Design Pattern, for instance.

Anyway, useful or not, that's just one idea I had in a 10-minutes car ride. I have no plans (neither time :-) to implement it, and it might not be as simple as it is described above - there are probably many corner cases to consider (like inner classes and generics), decisions to be made (for instance, it is clear that a subclass of a semifinal class must be defined as semifinal or final; but what about an overridden semifinal method?) and this is not just compiler fun (it might be in the case case of variables, but for methods and classes, that information must be somehow stored in the byteclass). But if someone has the nerves to give it a try, please let me know...

Bookmark blog post: del.icio.us del.icio.us Digg Digg DZone DZone Furl Furl Reddit Reddit
Comments
Comments are listed in date ascending order (oldest first) | Post Comment

  • Hmm.... I won't comment the cases related with variables: indeed they are typical problems of everyday's programming, nevertheless I'm unable to understand what kind of implications they have in case we try to give a well formulated description of the semifinal meaning. Furthermore I'm personally very conservative about language changes, and I don't see a good balance of costs/benefits here.

    It's far more interesting the case related to limiting extension of classes, considering that purely-polimorphic subclassing should be the only good way to use inheritance (this is related to the Liskov's substitution principle). Yes, I know that practically all frameworks violate it - amen - but an architect should try to comply with it whenever it's possible.

    Now, while in a "closed" project the architect should be in charge of deciding what OO strategy to use and should enforce it with programmers, he can't have the control in "open" projects, such as collaborative open source stuff. In this scenario, something like "semifinal" could be a good tool to enable a strong enforcement of design principles. In this case I think that, rather than a semifinal keyword, a compile-time annotation such as @PolymorphicExtensionOnly could do well.

    Posted by: fabriziogiudici on February 13, 2007 at 09:25 AM


  • I agree with Fabrizio, the class example can almost certainly be handled by an annotation in the same way as @Override works.

    The variable example is also a low level coding problem, but I'm not convinced that this is the right answer. I'll try and blog more on this at some point.

    Posted by: scolebourne on February 14, 2007 at 04:43 AM

  • I agree with Fabrizio as well - in fact, I think all kind of ´design by contract´ improvements should be done by annotations (there is even an open JSR for it).


    This new keyword should not been taken seriously, it was just an idea I had which could be an interested way to play around with javac and friends.

    Posted by: felipeal on February 14, 2007 at 05:21 AM

  • In a world where subclassing is used less and less, in favour of composition or mixins (or ad-hoc emulations of mixins, such as lots of static methods), I'm not sure why we'd need a keyword that mainly addresses a subclassing issue.

    The variables issue is easy to solve another way:

    final Object o;
    {
    final Object p=getObject();
    o=p==null ? new SomeObject() : p;
    }
    //now p is out of scope

    That can easily be abstracted to this:

    final Object o=ifNull(getObject(),{=>new SomeObject()});
    The ideal solution is that getObject() never returns null of course. Why are people still writing APIs that can return null?

    Posted by: ricky_clarkson on February 14, 2007 at 07:43 AM

  • This is interesting but I wouldn't call that semifinal. This is confusing because it sounds too much like the final modifier. I would rather call it "strict" or "rigid" or something like this.

    On the other hand I think that using a separate interface and factory is a way to do something similar to this.

    Posted by: eproulx on February 15, 2007 at 02:29 PM

  • What a waste of time :-) hahaha

    Posted by: denys_sene on February 16, 2007 at 10:14 AM

  • I introduced a somewhat different notion of "semifinal" a while back. My motivatin was also for the purpose of API development. However, the connotation is different...

    Semifinal on a method would allow non-package classes to call it, but not to override it. The motivation is defensive programming along the lines of what, I think, Joshua Block is urging in his book Effective Java.

    Adding semifinal to a method (or class) would prevent a client of an API from overriding a critical method and possibly breaking the API base class, while still allowing the API designer to override the method. Thus, semifinal would work like final for an API client, but not for an API designer (with package or private access).

    The main example cited in the following thread is to facilitate implementation of object wrappers, such as wrapping a modifiable object with an unmodifiable wrapper, with both the target and wrapper objects provided by the API designer, which employ defensive programming through the use of the semifinal keyword to prevent API clients from breaking the base class.

    http://forums.java.net/jive/thread.jspa?messageID=14094&tstart=0

    Posted by: jonbarril on February 26, 2007 at 10:56 AM

  • Joshua Block is urging in his book Effective Java. Adding semifinal to a method (or class) would prevent a client of an API from overriding a critical method and possibly breaking the API base class, while still allowing the API designer to override the method. Thus, semifinal would work like final for an API client, but not for an API designer (with package or private access). The main example cited in the following thread is to facilitate implementation of object wrappers, such as wrapping a modifiable object with an unmodifiable wrapper, with both the target and wrapper objects provided by the API designer, which employ defensive programming through the use of the semifinal keyword to prevent API clients from breaking the base class.


    Posted by: maripikos on June 17, 2007 at 01:42 PM



Only logged in users may post comments. Login Here.


Powered by
Movable Type 3.01D
 Feed java.net RSS Feeds