Skip to main content

Generic "this" ("self") method return type

4 replies [Last post]
peterkehl
Offline
Joined: 2005-01-28

Could we have way of declaring method return type to be its current (mplementation) subclass. Then calls on subclass instance could be easily chained.

Current way is to have override a method with its current class as return type. It calls parent method, and then returns this :

<br />
class Base {<br />
  protected final void setDo( Object key, Object value ) { /*do-what-told*/ }<br />
  public Base set( Object key, Object value ) { setDo( old, value ); return this; }<br />
}</p>
<p>class Child extends Base {<br />
  public Child set( Object key, Object value ) { setDo( key, value ); return this; }</p>
<p>  protected final void setSeveral( Map pairs ) {<br />
    for( final Map.Entry entry : pairs.entrySet() ) {<br />
      set( entry.getKey(), entry.getValue() );<br />
    }<br />
  }</p>
<p>  public Child setSeveral( Map pairs ) {<br />
    setDo( pairs );<br />
    return this;<br />
  }<br />
}<br />

This allows subclass to have new methods added, while both inherited and own methods can be called in chain (like StringBuffer):

<br />
new Child().set( "name", "Happy" ).set( mapOfKeyValuePairsToSet ).set( "description", "Friend" );<br />

However, that makes subclasses have non-creative Xyz(...)methods, which just:
1. narrow down return type, so that chained calls to own methods are possible
2. call parent XyzDo(...) method
3. return this

That makes subclasses:
1. awkward
2. pottentially out-of-contract, because child method can process additional/different code that just calling parent method and returning this

Above could be healed if there were a possibility to defined method return type to be "generic this", ie its current implementation class type. If we use <~> notation here, it would look like:

<br />
class Base {<br />
  public final <~> set( Object key, Object value ) {<br />
    /*do-what-told*/<br />
    return this;<br />
  }<br />
}</p>
<p>class Child extends Base {<br />
  public final <~> setSeveral( Map pairs ) {<br />
    for( final Map.Entry entry : pairs.entrySet() ) {<br />
      set( entry.getKey(), entry.getValue() );<br />
    }<br />
    return this;<br />
  }<br />
}</p>
<p>/* Then: */<br />
new Child().set( "name", "Smiling" ).setSeveral( map );<br />

I'm not sure how Javac and JVM would implement this. Maybe create a "shadow" void setSelfGeneric(Object,Object) method, and then create a bridge method to it in any subclass, which just calls it, and returns this.

If user were allowed to return a different Object than this, ie another Object of the same class as implementation, then it would need to check the type in runtime.

Interfaces could declare Self-Return method types as well.

Not sure whether Self-Return methods should be allowed not to be final (except when they're abstract). If subclass might change the behavior, then final Self-Return method can call a non-final protected method to do the job.

Reply viewing options

Select your preferred way to display the comments and click "Save settings" to activate your changes.
tackline
Offline
Joined: 2003-06-19

You can do some similar with only 1.5 facilities. Give the base class a generic parameter that represents a type "like this". Either cast this, or return the return value of an abstract "get this"/self method.

public abstract class Base {
private int x;
private int y;
@SuppressWarnings("unchecked")
public THIS location(int x, int y) {
this.x = x;
this.y = y;
return (THIS)this;
}
}
public class Concrete extends Base {
}

Or

public abstract class Base {
private int x;
private int y;
protected Base() {
assert this == getThis();
}
public abstract THIS getThis();
public THIS location(int x, int y) {
this.x = x;
this.y = y;
return getThis();
}
}
public class Concrete extends Base {
public Concrete getThis();
return this;
}
}

I must admit, I've only tried it once and didn't like it much in that particular situation.

Personally, I'd prefer a notation that allows a chain of method invocations on a single expression.

peterkehl
Offline
Joined: 2005-01-28

Thank you, Tackline.

It perfectly does the job.

kfgodel
Offline
Joined: 2005-12-22

Even though passing the concrete class in a type variable can fix your problem, I think it is cumbersome.
Imagine passing by type parameter an already parametrized class. Your typing can grow exponentially, and your clarity become null very quickly.
I still think that a way of saying something like "this" for the actual concrete type is necessary and serves the clarity of expressions in the language

peterkehl
Offline
Joined: 2005-01-28

It would also clarify behavior of Object.getClass(), which must have special support of compiler, as its Javadoc says:

"Returns:

The java.lang.Class object that represents the runtime class of the object. The result is of type Class where X is the erasure of the static type of the expression on which getClass is called."