Skip to main content

semifinal keyword

24 replies [Last post]
jonbarril
Offline
Joined: 2004-12-15

I suggest introducing the keyword "semifinal" (or some such suitable variant). The use of this keyword for a method would allow private and package visible classes to override the method, but block protected and public visible classes from overriding them.

The motivation is that often it is desirable to declare a method public and final to allow non-package classes to call the method while preventing them from overriding the method (because the subclass might break the base class). However, declaring a method as final also prevents private and package classes from overriding such methods, which is commonly needed to create wrapper classes. Introduction of the semifinal keyword allows finer control over the notion of finality.

Reply viewing options

Select your preferred way to display the comments and click "Save settings" to activate your changes.
jonbarril
Offline
Joined: 2004-12-15

I'm not sure what it is you disapprove of. Is it the desire to implement a heavyweight wrapper pattern?

In any case, as I mentioned in my earlier post, such an approach of having impl methods for each mutator can become onerous if there are lots of mutator methods involved.

For example, I wanted to implement special Set and Map classes. Because of the complexity of implementation it was easier to not make it an interface, and instead implement Map directly in the base class. To create an unmodifiable wrapper (as distinct from an immutable class) requires overridding a lot of methods in the base class. Using the prescribed technique would mean having an impl for each one.

--jon

hlovatt
Offline
Joined: 2003-11-18

I don't find the getView style all that good in either form you describe, i.e. either returning this but saying don't change anything in the JavaDoc or when returning this wrapped in an unmodifiable wrapper. The problem is that the object I get when I call getView isn't immutable; even if I don't change it in my code someone else's code can change it, therefore its guarantee of immutability is too small for me.

I don't think I am alone in this, for example Joshua Bloch in Effective Java recommends immutable classes. Further, I quite like having the compiler enforce this immutability, see URL above.

If you like immutability then you can vote for it here: http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=4617197

jonbarril
Offline
Joined: 2004-12-15

Block is actually one of the motivations for such wrapper-based unmodifiable views. It is all in the name of defensive programming...

(Bloch, pg 125)
"Arguably, the real lesson in all of this is that you should, where possible, use immutable objects as components of your objects so that you don't have to worry about defensive copying."

All very true. However, another way to avoid defensive copying is to return an unmodifiable view. This is a well established pattern when using the collections package. The intent is NOT for the view to be immutable: The view is a live one, almost as if the client held a reference to the object. And, by returning a view, the client can choose whether to create a static copy of the data, or to use it as a live view.

Say you have host object whose state consists of a collection. The host can mutate the collection. If a client wants to see the state of the collection for whatever reason, the host can either clone a copy and return it, copy the contents into a return value object provided by the client, or return a (preferably singleton) unmodifiable view of the object.

The last one is based on a wrapper class (discussed in Item 14 of Bloch). The twist that I have been using is allowing the wrapper to test equal to the wrapper target without exposing itself (the SELF problem Block discusses). And furthermore, the wrapper class is based on the decorator pattern, and the essence of the decorator pattern is that a decorator can decorate its own type (a wrapper of a wrappper of a wrapper, etc)

So, to make a long story short, if you really buy into wrapper classes whether for unmodifiable views, thread safety, or whatever, then the final modifier for a method is too blunt an instrument, hence the request for a semifinal variation.

--jon

hlovatt
Offline
Joined: 2003-11-18

When you want an unmodifiable view of an object that can be modified; I find it best to use a change listener that sends an immutable copy to each of its registered listeners when it changes, e.g.:

[code]
interface FooListener { void fooChanged( ImmutableFoo foo ); }

class ValueFoo {
private final List listeners = new ArrayList(); }

// Assuming synchronization is necessary
synchronized ImmutableFoo addListener( final FooListener listener ) {
listners.add( listener );
return new ImmutableFoo( this );
}

synchronized void notifyListeners() {
final ImmutableFoo immutable = new ImmutableFoo( this );
for ( final Iterator i = listeners.iterator(); i.hasNext(); ) {
final FooListener listener = (FooListener) i.next();
listener.fooChanged( immutable );
}
}

// Rest ... (they call notifyListeners if they make a change)
}
[/code]

I find the above pattern particularly useful in a multi-threaded environment. I am not disagreeing with you that a wrapper can't be used, it is just that I find the immutable object easier and using the PEC (https://pec.dev.java.net/nonav/compile/index.html) I can find coding errors easily.

jonbarril
Offline
Joined: 2004-12-15

I have not seen this one. Interesting, although, it does make for extra object creation and event handling when a change occurs, as opposed to an unmodifiable view. I think there is an important distinction and role for immutable versus unmodifiable.

Another way to look at it is that the change notifier approach you suggest is a "pushed" read-only view of the target object, and an unmodifiable view is a "pulled" read-only view of the target object.

--jon

hlovatt
Offline
Joined: 2003-11-18

This is the standard event programming model, e.g. Swing. I have not found the performance overhead of object creation to be a problem in practice, it creates one object and pushes this to all the listeners. You can do a pull version if you like:

[code]
class ValueFoo {
private ImmutableFoo cache = null;

/* Assuming synchronization is necessary */
synchronized ImmutableFoo getImmutable() {
if ( cache == null ) cache = new ImmutableFoo( this );
return cache;
}

/* Rest ... (they set cache to null if they make a change) */
}
[/code]

The client code doesn't have it's own copy of cache, it calls getImmutable each time.

I generally find the push version easier, but both work. The reason for favoring the push version is that it naturally schedules the task flow in a typically Model View Controller (MVC) pattern, e.g. there is no need for the views to do anything until the model changes.

Using the MVC pattern I put the listener code in the controller so that I don't have to repeat the code in each model, the model is a Value semantics type with a companion Immutable type.

mason
Offline
Joined: 2003-06-14

JUnit testing. It's nice to have your TestCase be able to check that fooMethod() does, in fact return barObject, but you'd never in your life want any other class to actually be able to directly access fooMethod(), it's just too dangerous.

The best you can do in this case is mark them as "package" protected and drop all your test cases in the same package as your code. This may work some of the time, but it makes a headache when it comes to deployment, especially if you've got lots of classes..

trevorwilliams
Offline
Joined: 2004-11-08

Wouldn't this case be more than adequately handled with the reflection API? You could examine the Method instance directly, or if you really need to invoke a private method, call setAccessible(true) first.

jwenting
Offline
Joined: 2003-12-02

-100

Another completely useless new keyword. Learn to use final appropriately and be done with it.

Final is designed to prevent overriding. If you want to override it, don't make it final.

If you don't want classes from other packages using your class, don't make it public.

If you want outside classes to have access but not to override it, make a final wrapper class around it.

If you want total idiocy, use C++

jonbarril
Offline
Joined: 2004-12-15

Please read the entire thread. If only life and software were as black and white as you make it out to be.

--jon

jwenting
Offline
Joined: 2003-12-02

your entire reasoning is prevented by using proper OO. Therefore learn proper OO and stop screaming for Java to be turned into a mess.

jonbarril
Offline
Joined: 2004-12-15

I would be most appreciative if you could describe to me how wrapper classes and defensive programming are not OO. While you are at it, you might want to copy Joshua Bloch on this as, according to his book, he too seems to be an advocate of wrapper classes and defensive programming.

--jon

jonbarril
Offline
Joined: 2004-12-15

This issue didn't seem to gain traction, but I find it to be a critical one for good defensive programming. Perhaps the motivation was unclear. I'll provide a short example...

Say I am developing a package for use by a client that contains the class MyClass, and an unmodifiable wrapper for it, UnmodMyClass. I want to allow the client to extend the class, but not to override the set() method, since it may break the base class, MyClass.

public class MyClass {
public semifinal void set(int val) {...}
public int get() {...}
}

public class UnmodMyClass extends MyClass {
public UnmodMyClass(MyClass wrapperTarget) {...}

// semifinal in base allows package to override
public void set(int val) {
throw new UnsupportedOperationException()
}
}

Note that without a "semifinal" keyword, either the client can override set(), which requires extra internal impl methods cluttering the base class to assure safety; or, final must be used, with MyClass implementing unmodifiability internally, as a mode. In either case, the use of interfaces does not help, and lack of semifinal encourages non-defensive programming and leads to rather cluttered code, especially if lots of methods are involved.

--jon

hlovatt
Offline
Joined: 2003-11-18

I can think of two solutions to your problem:

1. Declare an interface and use composition (wrapper), e.g.:

[code]
// Package writer's code
package myPackage;

public interface MyInterface {
void set( int val );
int get();
}

public final class MyClass implements MyInterface { // note class final, could also just make get and set final
// ...
}

// User's code
package somethingElse;

public final class YourClass implements MyInterface {
private final MyClass myclass;
public YourClass( final MyClass myClass ) { this.myClass = myClass; }
public int get() { return myClass.get(); }
public void set( final int val ) { myClass.set( val ); }
// ...
}
[/code]

2. Add the final keyword only to the public classes not to base classes that have package access, e.g.:

[code]
// Package writer's code
package myPackage;

class MyBaseClass {
public void set( final int val ) { ... }
public int get() { ... }
// ...
}

public class MyClass extends MyBaseClass {
public final void set( final int val ) { super( val ); }
public final int get() { return super(); }
}

// User's code
package somethingElse;

public final class YourClass extends MyClass {
// ...
}
[/code]

Couldn't you use one of these instead of yet another keyword and yet more semantics?

jonbarril
Offline
Joined: 2004-12-15

The problem with "1. Declare an interface and use composition (wrapper)" is that the supplier often wants to strictly control the machinery in the base class, and require that the client use it and only it. Providing an interface, besides adding to the clutter, separates the type from its implementation, which not what is always wanted.

The problem with "2. Add the final keyword only to the public classes not to base classes that have package access" is that both MyClass and UnmodMyClass are public classes intended for use by the client. In other words, the user is allowed to choose whether to use a modifiable or an unmodifiable version, but for defensive reasons, the set() method must not be overridden by the client.

A further complication is that I often want to use MyClass instances in a collection. Furthermore, I also want to use UnmodMyClass instances in collections, with the unmod instance being equal to the mod instance (i.e. a wrapper pattern where the wrapper is equal to the wrapper target and can be used interchangeably).

Introduction of a semifinal keyword (or some such combination of existing keywords) would go far to allowing some of these more advanced variations on the basic wrapper pattern (heavyweigth wrapping instead of the usual lightweight wrapping).

--jon

hlovatt
Offline
Joined: 2003-11-18

You can use the code below and program to the interface AbstractInteger, e.g. List< AbstractInteger >.

[code]
public abstract class AbstractInteger {
public abstract void set( int value );
public abstract int get();
public final boolean equals( final Object other ) {
if ( this == other ) return true;
if ( !(this instanceof AbstractInteger) ) return false;
final AbstractInteger that = (AbstractInteger) other;
return get() == that.get();
}
// ...
}

public class ImmutableInteger extends AbstractInteger {
private final int value;
public ImmutableInteger( final int value ) { this.value = value; }
public final void set( final int notUsed) { throw new UnsupportedOperationException(); }
public final int get() { return value; }
}

public class ValueInteger extends AbstractInteger {
private int value;
public ImmutableInteger( final int value ) { this.value = value; }
public final void set( final int value ) { this.value = value; }
public final int get() { return value; }
}
[/code]

Also you insert into the heirarchy at any point package access classes to give finer control of what is final when.

Here is a compiler that extends Java and provides compile time checks for immutability that may be useful if you want this style of programming:

https://pec.dev.java.net/nonav/compile/index.html

jonbarril
Offline
Joined: 2004-12-15

Thanks for the sticking with this. I now see that what is central to what I am trying to do is the notion of wrapping (as I call it, heavyweight wrapping), with wrappers being able to wrap the class or another wrapper. I am involved in developing a framework involving, and wrappers are a great way to achieve certain runtime assurances, such as unmodifiability.

Thus, the supplier could provide MyClass and several wrapper versions, such as UnmodMyClass and SynchronizedMyClass. Thus, no matter what flavor of MyClass a client was given, he could always assure that it was unmodifiable by wrapping it with UnmodMyClass before passing it on as a reference.

--jon

tackline
Offline
Joined: 2003-06-19

I'm not sure I approve of what you are trying to achieve, but there is a simpler method of achieving the required behaviour. Declare the method as public final in the base class. The implementation should just forward to an implementation method. The implementation method should be package private but not final. Package privacy ensures it can be overriden but not be classes outside the package. For instance:

public abstract class Component {
public final void dispatchEvent(AWTEvent e) {
dispatchEventImpl(e);
}
void dispatchEventImpl(AWTEvent e) {
...
}
...
}
public class Container extends Component {
@Override
void dispatchEventImpl(AWTEvent e) {
...
}
...
}

hlovatt
Offline
Joined: 2003-11-18

Yep. This is another valid approach. I am not sure that it is any simpler, just different. With the approach I suggested above, AbstractInteger, ImmutableInteger, and ValueInteger, there is a compiler that can check that ImmutableInteger is really immutable and that both ImmutableInteger and ValueInteger have value semantics:

https://pec.dev.java.net/nonav/compile/index.html

This extra type checking is valuable in itself and in addition the compiler supports:

1. Conversions by copying between the Value and Immutable types

2. ArrayLists of value and immutable types

jonbarril
Offline
Joined: 2004-12-15

The JDK is rife with examples of unmodifiable wrappers, where there is no way to identify an unmodifiable instance. Detecting an unmodifiable instance is not really necessary. What is necessary is for the provider of an object to have a way to assure that the client cannot modify the state of an object that thye client should not be modifying, such as with an unmodifiable wrapper.

Say I have a host class that wants to expose a view of itself or some aspect of its state, as represented by a reference to an object. The host class would expose a getView() method, with the method contract stating that this is a live view of the object and the client should not modify its state (i.e. the view is output only). As such, the host class can either trust that the client will not modify the object, or defensively wrap the object in an unmodifiable wrapper.

With final for a method being final for everyone, often extra interfaces and impl methods must be employed, as described in the preceding discussions, to achieve what would otherwise be fairly straightforward wrapper classes.

--jon

denismo
Offline
Joined: 2003-06-28

Indeed, inheritance and access restrictions need be made different. AWT has many methods that must be/are final, but need to be overridden by Swing, and only Swing. semifinal won't help here, but "friends" feature will help, and it also can be used instead of "semifinal".

subanark
Offline
Joined: 2004-11-26

No,no,no,no!

Swing should be as much as possible independent of AWT. What swing implements should be implementable in user code (in an untrusted envrioment).

saintjohn
Offline
Joined: 2004-10-25

next step - introducing of "quarterfinal" keyword :)

alexlamsl
Offline
Joined: 2004-09-02

I concur - I thought about the lines of having a JLS contest as soon as I saw the title :D