Java Solaris Communities Sun Store Join SDN My Profile Why Join?
 
Bug Database
Bug Detail
Quick Lists
Top 25 Bugs
Top 25 RFE's
Recently Closed Bugs
Printable Page Printable Page


Bug Database
Bug ID: 6479372
Votes 17
Synopsis Add self types (type of 'this' aka ThisClass) to the language
Category java:specification
Reported Against
Release Fixed
State 4-Defer, request for enhancement
Priority: 5-Very Low
Related Bugs 6373386 , 4957174 , 6202132
Submit Date 06-OCT-2006
Description
A DESCRIPTION OF THE REQUEST :
The SelfType pattern (which goes by many names, and is closely related to the problem described in closed bug 6431633), in concept, is extremely useful for more sophisticated applications of generics.

The SelfType pattern in reality is a limited workaround for situations requiring the use the type of THIS class in the class definition. It takes the familiar form...

abstract class AbstractClass<THIS extends AbstractClass<THIS>> {
    abstract public THIS getThis();
    public void setPeer(THIS peer) {_peer = peer;}
    private THIS _peer;
}

class ConcreteClass extends AbstractClass<ConcreteClass> {
    public ConcreteClass getThis() {return this;}
}

Unfortunately, concrete classes, such as ConcreteClass cannot be extended with "this-awareness". Thus...

class ConcreteSubClass extends ConcreteClass {}

   ConcreteClass obj = new ConcreteClass();
   ConcreteSubClass subobj = new ConcreteSubClass();

    subobj.setPeer(obj); // !!!should be an error, but thisness is lost

The problem becomes even worse if you want two this-aware generic classes that mutually reference one another...

public abstract class AbstractPeer<THIS extends AbstractPeer<THIS,THAT>,
THAT extends AbstractPeer<THAT,THIS>> {
	public void setPeer(THAT peer) {
		_peer = peer; // this references that
		_peer.setPeer(getThis()); // that references this
	}
	
	public THAT getPeer() {
		return _peer;
	}
	
	public abstract THIS getThis();
	
	private THAT _peer;
}

public class AlphaPeer<THAT extends BetaPeer<AlphaPeer<THAT>>>
extends AbstractPeer<AlphaPeer<THAT>,THAT> { // !!!does not compile
	public AlphaPeer<THAT> getThis() {
		return this;
	}
}

public class BetaPeer<THAT extends AlphaPeer<BetaPeer<THAT>>>
extends AbstractPeer<BetaPeer<THAT>,THAT> { // !!!does not compile
	public BetaPeer<THAT> getThis() {
		return this;
	}
}



JUSTIFICATION :
Imagine if  the java language spec were to say that a concrete class could only be extended once.  Without some inherent support for a THIS type, that is essentially what is happening (and a lot more) in more sophisticated attempts at employing generics for code reusability.



EXPECTED VERSUS ACTUAL BEHAVIOR :
EXPECTED -
A robust this-awareness in generic classes, where concrete classes can be correctly extended, and where mutual references can be properly defined
ACTUAL -
A wimpy this-awareness in generic classes, which relies on generic constructs approaching the level of hieroglyphics (Foo<THIS extends Foo<THIS>)
Posted Date : 2006-10-06 21:21:08.0
Work Around
N/A
Evaluation
I think the submitter is looking for something like this:

class Foo {
    protected this clone() {
        return (this) super.clone();
    }
}
Posted Date : 2006-10-06 22:47:04.0

Other languages, notably Strongtalk (http://www.strongtalk.org/), have
used self types.  To type check any Smalltalk variant, the this type is
essential.  However, it does not come without restrictions, for example,
it can only be used in covariant places (return types as in the above
example, not method parameter types).

If self types were added to the language, it would be natural to consider
the return type of clone.  However, changing the return type of clone to
use a self type would not be compatible with existing applications and
likely to cause a lot of problems.

In general, the impact on the rest of the language from adding self type
is likely to be just as big as adding generic types.  Contrary to Strongtalk,
the use in Java would be limited and covariant return types can be used
to solve most of the problems that can be solved with self types.

So it is not likely that we will see self types in the Java programming
language.
Posted Date : 2006-10-09 18:33:22.0

Kim Bruce and Nate Foster have studied this extensively:
http://www.cis.upenn.edu/~jnfoster/papers/looj.pdf

ThisClass/ThisType is useful for any binary method, not just "more sophisticated applications of generics" as in the Description.
Posted Date : 2006-11-09 16:14:33.0
Comments
  
  Include a link with my name & email   

Submitted On 31-OCT-2006
jonbarril
A correction to my original submission:

The self-type pattern for generics is like not being able to fully subclass a "concrete" class.  You can only fully subclass an abstract class, and subclassing a concrete class results in a half-baked version of a subclass, with the "this" type parameters and returns being that of the concrete super class, not the subclass.

Response to the evaluation:

Do a google search for "java generic self type".  There is an awful lot of talk out there about a need for this, and what a pain it is not having it.

Covariant return just doesn't cut it.  It is difficult to get it to work in the context of the self-type pattern, and does nothing for method parameters, resulting in a half-baked concrete subclass.  As we all know, something that is half-baked is often worse than not having it at all because the inconsistencies in usage will drive you (designer and client) up the wall.

I can still remember the time when the java high priests swore that you'd never see generics in java, yet we now have generics.  Might i suggest that the high priests give this problem a bit more thought before abandoning it.

 I have developed a number of patterns for highly reusable code that don't quite work because of the lack of a strong sense of a self-type -- i.e. the ability to fully subclass a concrete class that relies on the self type.  It seems a lot of folks out there are making do, but a major avenue of code reusability through the self type is stymied.

As for your example using clone(), it seems to me that  super.clone() cannot be cast to "this" since the super class is not assignable to the "this" subclass.  The notion of  "this" is exactly what it says -- the type of "this" declared class, and the type to which any subclass of the "this" class can be assigned to.

Also, clone() may be an issue, but I have not seen it come up in the community that is discussing self-type.  Why not just leave clone() and other such legacy methods alone for now (returning Object would be no worse than what we now have), and focus on the crux of the problem, which is the use of self-type in new highly reusable code.


Submitted On 04-NOV-2006
jonbarril
Given the current lack of a true self-type, the following is an example of the closest that I've been able to come to achieving generic "this-ness".  I call it the RawType pattern, since it relies on the use of the raw type (and hence, has lots of compiler warnings, and other serious drawbacks, but no compiler errors).

==========

/**
 * Pros: For variables, can consistently use the raw type. Only simple casting
 * to (THIS) is sometimes needed.
 * 
 * Cons: Lots of compiler warnings because of raw type. This-ness of methods
 * using THIS as an argument or return value is NOT inherited by subclasses,
 * requiring override in all descendant subclasses.
 * 
 * @author Jon Barrilleaux (jonb@jmbaai.com) of JMB and Associates Inc.
 * @version $Revision: 1.1 $
 */
public interface RawType<THIS extends RawType> {	
	public THIS getThis();
	public THIS asUnmod();
}

===================
/**
 *
 * @author  Jon Barrilleaux (jonb@jmbaai.com) of JMB and Associates Inc.
 * @version $Revision: 1.1 $
 */
public interface MyObject<THIS extends MyObject>
extends RawType<THIS> {
	public THIS asUnmod();
	public THIS getThis();
	
	public void setThisObject(THIS obj);
	public THIS getThisObject();
	
	public void setMyObject(MyObject obj);
	public MyObject getMyObject();
	
	// class

	/**
	 * Default concrete implementation for instantiation.
	 */
	public static class Impl extends Base<MyObject> {		
		public final MyObject asUnmod() {
			return new MyObject.Unmod<MyObject>(getThis()){};
		}
	}

	/**
	 * Default abstract implementation for extension.
	 */
	public static abstract class Base<THIS extends MyObject>
	implements MyObject<THIS> {
		public final void setThisObject(THIS obj) {
			_obj = obj;
		}
		
		public final THIS getThisObject() {
			return _obj;
		}
		
		public final void setMyObject(MyObject obj) {
			_myObj = obj;
		}
		
		public final MyObject getMyObject() {
			return _myObj;
		}

		public final THIS getThis() {
			return (THIS)this;
		}
		
		// personal
		
		private THIS _obj;
		private MyObject _myObj;
	}

	/**
	 * Abstract unmodifiable wrapper for extension.
	 */
	public static abstract class Unmod<THIS extends MyObject>
	implements MyObject<THIS> {
		public Unmod(THIS target) {
			_target = target;
		}

		public final MyObject getMyObject() {
			return _target.getMyObject();
		}

		public final THIS getThisObject() {
			return (THIS)_target.getThisObject();
		}

		public final void setMyObject(MyObject obj) {
			throw new UnsupportedOperationException();
		}

		public final void setThisObject(THIS obj) {
			throw new UnsupportedOperationException();
		}

		public final THIS getThis() {
			return (THIS)this;
		}

		public final THIS asUnmod() {
			return getThis();
		}
		
		// personal
		
		private THIS _target;
	}
}


Submitted On 04-NOV-2006
jonbarril
================

/**
 *
 * @author  Jon Barrilleaux (jonb@jmbaai.com) of JMB and Associates Inc.
 * @version $Revision: 1.1 $
 */
public interface MySubObject<THIS extends MySubObject>
extends MyObject<THIS> {
	public THIS asUnmod();
	public THIS getThis();
	
	public void setThisObject(THIS obj);
	public THIS getThisObject();
	
	public void setMyObject(MyObject obj);
	public MyObject getMyObject();
	
	public void setMySubObject(MySubObject obj);
	public MySubObject getMySubObject();
	
	// class

	/**
	 * Default concrete implementation for use.
	 */
	public static final class Impl extends Base<MySubObject> {
		public final MySubObject asUnmod() {
			return new MySubObject.Unmod<MySubObject>(this){};
		}
	}

	/**
	 * Default abstract implementation for extension.
	 */
	public static abstract class Base<THIS extends MySubObject>
	extends MyObject.Base<THIS> implements MySubObject<THIS> {
		public final void setMySubObject(MySubObject obj) {
			_mySubObj = obj;
		}
		
		public final MySubObject getMySubObject() {
			return _mySubObj;
		}
		
		// personal
		
		private MySubObject _mySubObj;
	}

	/**
	 * Abstract unmodifiable wrapper for extension.
	 */
	public static abstract class Unmod<THIS extends MySubObject>
	extends MyObject.Unmod<THIS> implements MySubObject<THIS> {
		public Unmod(THIS target) {
			super(target);
			_target = target;
		}

		public MySubObject getMySubObject() {
			return _target.getMySubObject();
		}

		public void setMySubObject(MySubObject obj) {
			throw new UnsupportedOperationException();
		}
		
		// personal
		
		private THIS _target;
	}
}


Submitted On 04-NOV-2006
jonbarril
=======================

/*
 *	Project Gumbo - gumbo.sourceforge.net
 *	$Id: Test.java,v 1.1 2006/11/03 07:43:22 jonb Exp $
 *
 * This source is licensed under the GNU LGPL v2.1.
 * Please read http://www.gnu.org/copyleft/lgpl.html for more information.
 *
 * This software comes with the standard NO WARRANTY disclaimer for any
 * purpose.  Use it at your own risk.
 */
package proto.java.generic.rawtype;


/**
 *
 * @author  Jon Barrilleaux (jonb@jmbaai.com) of JMB and Associates Inc.
 * @version $Revision: 1.1 $
 */
public class Test A {
	public void testImpl() {
		MyObject obj = new MyObject.Impl();
		MySubObject subobj = new MySubObject.Impl();
	}
		
	public void testMyObject() {
		MyObject obj = null;
		MyObject.Base objB = null;
		MyObject.Impl objI = null;
		MySubObject subobj = null;
		MySubObject.Base subobjB = null;
		MySubObject.Impl subobjI = null;
		
		obj = obj;
		obj = objB;
		obj = objI;
		obj = subobj;
		obj = subobjB;
		obj = subobjI;
	}
		
	public void testMyObjectBase() {
		MyObject obj = null;
		MyObject.Base objB = null;
		MyObject.Impl objI = null;
		MySubObject subobj = null;
		MySubObject.Base subobjB = null;
		MySubObject.Impl subobjI = null;
		
		objB = obj;
		objB = objB;
		objB = objI;
		objB = subobj;
		objB = subobjB;
		objB = subobjI;
	}
	
	public void testMyObjectImpl() {
		MyObject obj = null;
		MyObject.Base objB = null;
		MyObject.Impl objI = null;
		MySubObject subobj = null;
		MySubObject.Base subobjB = null;
		MySubObject.Impl subobjI = null;
		
		objI = obj;
		objI = objB;
		objI = objI;
		objI = subobj;
		objI = subobjB;
		objI = subobjI;
	}
		
	public void testMySubObject() {
		MyObject obj = null;
		MyObject.Base objB = null;
		MyObject.Impl objI = null;
		MySubObject subobj = null;
		MySubObject.Base subobjB = null;
		MySubObject.Impl subobjI = null;
		
		subobj = obj;
		subobj = objB;
		subobj = objI;
		subobj = subobj;
		subobj = subobjB;
		subobj = subobjI;
	}
		
	public void testMySubObjectBase() {
		MyObject obj = null;
		MyObject.Base objB = null;
		MyObject.Impl objI = null;
		MySubObject subobj = null;
		MySubObject.Base subobjB = null;
		MySubObject.Impl subobjI = null;
		
		subobjB = obj;
		subobjB = objB;
		subobjB = objI;
		subobjB = subobj;
		subobjB = subobjB;
		subobjB = subobjI;
	}
	
	public void testMySubObjectImpl() {
		MyObject obj = null;
		MyObject.Base objB = null;
		MyObject.Impl objI = null;
		MySubObject subobj = null;
		MySubObject.Base subobjB = null;
		MySubObject.Impl subobjI = null;
		
		subobjI = obj;
		subobjI = objB;
		subobjI = objI;
		subobjI = subobj;
		subobjI = subobjB;
		subobjI = subobjI;
	}
}
	


Submitted On 04-NOV-2006
jonbarril
/**
 *
 * @author  Jon Barrilleaux (jonb@jmbaai.com) of JMB and Associates Inc.
 * @version $Revision: 1.1 $
 */
public class TestB  {

	public void testMyObjectGet() {
		MyObject obj = null;
		
		obj = obj.getThisObject();
		obj = obj.getThisObject().getThisObject();
		obj = obj.getThisObject().getMyObject();
		obj = obj.getThisObject().getMySubObject();
		
		obj = obj.getMyObject();
		obj = obj.getMyObject().getThisObject();
		obj = obj.getMyObject().getMyObject();
		obj = obj.getMyObject().getMySubObject();
		
		obj = obj.getMySubObject();
		obj = obj.getMySubObject().getThisObject();
		obj = obj.getMySubObject().getMyObject();
		obj = obj.getMySubObject().getMySubObject();
	}	
	
	public void testMySubObjectGet() {
		MySubObject subObj = null;
		
		subObj = subObj.getThisObject();
		subObj = subObj.getThisObject().getThisObject();
		subObj = subObj.getThisObject().getMyObject();
		subObj = subObj.getThisObject().getMySubObject();
		
		subObj = subObj.getMyObject();
		subObj = subObj.getMyObject().getThisObject();
		subObj = subObj.getMyObject().getMyObject();
		subObj = subObj.getMyObject().getMySubObject();
		
		subObj = subObj.getMySubObject();
		subObj = subObj.getMySubObject().getThisObject();
		subObj = subObj.getMySubObject().getMyObject();
		subObj = subObj.getMySubObject().getMySubObject();
	}	
	
	public void testMyObjectSet() {
		MyObject obj = null;
		MySubObject subObj = null;
		
		obj.setThisObject(obj);
		obj.setThisObject(obj.getThisObject());
		obj.setThisObject(obj.getMyObject());
		obj.setThisObject(obj.getMySubObject());
		obj.setThisObject(subObj);
		obj.setThisObject(subObj.getThisObject());
		obj.setThisObject(subObj.getMyObject());
		obj.setThisObject(subObj.getMySubObject());
		
		obj.setMyObject(obj);
		obj.setMyObject(obj.getThisObject());
		obj.setMyObject(obj.getMyObject());
		obj.setMyObject(obj.getMySubObject());
		obj.setMyObject(subObj);
		obj.setMyObject(subObj.getThisObject());
		obj.setMyObject(subObj.getMyObject());
		obj.setMyObject(subObj.getMySubObject());
	}	
	
	public void testMySubObjectSet() {
		MyObject obj = null;
		MySubObject subObj = null;
		
		subObj.setThisObject(obj);
		subObj.setThisObject(obj.getThisObject());
		subObj.setThisObject(obj.getMyObject());
		subObj.setThisObject(obj.getMySubObject());
		subObj.setThisObject(subObj);
		subObj.setThisObject(subObj.getThisObject());
		subObj.setThisObject(subObj.getMyObject());
		subObj.setThisObject(subObj.getMySubObject());
		
		subObj.setMyObject(obj);
		subObj.setMyObject(obj.getThisObject());
		subObj.setMyObject(obj.getMyObject());
		subObj.setMyObject(obj.getMySubObject());
		subObj.setMyObject(subObj);
		subObj.setMyObject(subObj.getThisObject());
		subObj.setMyObject(subObj.getMyObject());
		subObj.setMyObject(subObj.getMySubObject());
		
		subObj.setMySubObject(obj);
		subObj.setMySubObject(obj.getThisObject());
		subObj.setMySubObject(obj.getMyObject());
		subObj.setMySubObject(obj.getMySubObject());
		subObj.setMySubObject(subObj);
		subObj.setMySubObject(subObj.getThisObject());
		subObj.setMySubObject(subObj.getMyObject());
		subObj.setMySubObject(subObj.getMySubObject());
	}	
}


Submitted On 05-NOV-2006
sj_colebourne
This problem is not just limited to clone(). It has a big impact on immutable class design, where you need immutable mutators to return the type of the subclass not the superclass. In this scenario, you can end up repeating vast numbers of methods each of which just do super.xxx() in order to invoke the convariant return type.

Enhancing generics with this feature would be relatively simple, and would save a lot of lines of meaningless boilerplate code. And aren't immutable classes meant to be the way of the future?


Submitted On 06-NOV-2006
jonbarril
Ditto for unmodifiable classes, such as the Unmod wrapper classes in the examples above (note that most of the methods in the base class, the implementation class, and the wrappers are intentionally made final).

As formalized by Bloch in "Effective Java" (and no doubt many others before and after), classes should be designed for extension, which means that methods that are not intended to be extended should be final.  This is the main reason for the odd, repetitive structure of the examples I included above.  Given the current state of Java there is no way to write a base class with final methods that can be wrapped with an unmodifiable (or synchronized, or null object, etc) wrapper -- you have to define an interface, and then have a "family" of classes that implement the interface, which can declare the methods as final.   As such, and as the previous commentor has correctly observed, you end up with a whole lot of boilerplate just to achieve a modicum of good solid reusable code.  And, generics has, in many cases, exaccerbated this problem, not solved it.


Submitted On 26-JAN-2007
Miamidot
Would be useful for getting log4j handles.

 private static Log LOG =
  LogFactory.getLog(ThisClass);

Currently we have to modify the class name for the thousands of classes of each project to register log4j for each class.

As according to author of this issue, the following convenience should be provided,

class LinkLink{
 public mkLink(ThisClass cref, SomeClass xref)
 { ... }

rather than,

class LinkLink{
 public mkLink(LinkLink cref, SomeClass xref)
 { ... }




Submitted On 23-FEB-2007
Compl.Y.Still
I wonder how you've made the tricky javac to workaround Class<?> Object.getClass(); where:
"The result is of type Class<? extends X> where X is the erasure of the static type of the expression on which getClass is called."

Can't this be extended to a wider scope and with more formal syntax? such like the 'class' keyword in place of a type name?


Submitted On 13-APR-2007
theshade
Although this proposal has other uses, I'd like to point out that the use of method chaining is actually a work-around in the Java language for the with/endwith construct from for example Pascal.

Constructs like this are possible in Pascal:

WITH object1 BEGIN
  .setTitle("My Title")
  WITH .getAddress() BEGIN
     .setStreetName("My Street")
  END
END

The Java equivalent being used these days with method chaining looks something like this:

object1
  .setTitle("My Title")
  .getAddress()
     .setStreetName("My Street");

Unfortunately it has numerous problems, some of which is being addressed by this RFE.

The power of method chaining (or the with/endwith construct) should be obvious when creating hierarchical structures in Java, like for example in Swing.  Consider this Swing example:

{
    JPanel panel1 = new JPanel();

    panel1.setBackground(Color.RED);

    JButton button1 = new JButton("Ok");

    button1.setBackground(Color.GREEN);

    JButton button2 = new JButton("Cancel");

    button2.setBackground(Color.RED);

    panel1.add(button1);
    panel1.add(button2);

    return panel1;
}

The example is very cumbersome.  You are forced to declare various pointless variables to temporary hold objects so you can modify them, which makes the code hard to read and hard to re-use (can't copy and paste a piece of Swing UI code easily elsewhere).

With method chaining the example could look like this:

{
    return new JPanel()
        .setBackground(Color.RED)
        .add(new JButton("Ok")
            .setBackground(Color.GREEN))
        .add(new JButton("Cancel")
            .setBackground(Color.RED));
}

The above example suffers from the problem though that superclasses do not return this.getClass() as their return type.

With a with/endwith construct it could look like this:

{
    return with new JPanel() {
       .setBackground(Color.RED);
       with(.add(new JButton("Ok")) {
          .setBackground(Color.GREEN);
       }
       with(.add(new JButton("Cancel")) {
          .setBackground(Color.RED);
       }
   }
}

Method chaining is an acceptable compromise at the moment but the underlying reason that it is being used so extensively in a lot of frameworks is in part the lack of a way to access objects multiple times without having to declare pointless temporary variables.  With/Endwith constructs addressed this need in various other languages.  Method chaining in part can address this for Java.


Submitted On 13-APR-2007
theshade
Slight typo in the last example, it should read:

{
    return with(new JPanel()) {
       .setBackground(Color.RED);
       with(.add(new JButton("Ok")) {
          .setBackground(Color.GREEN);
       }
       with(.add(new JButton("Cancel")) {
          .setBackground(Color.RED);
       }
   }
}


Submitted On 09-MAY-2007
Hi,

I have needed this behavior for a while now.  I have been able to sort of simulate it using the obscure syntax for explicit type parameters.   It's pretty cool take a look.

public class TestGetThis {

	public static void main(String[] args) {
		new TestGetThis().run();
	}

	void run() {
		SubClass1 subClass1 = new SubClass1();
		subClass1.callBaseMethodWithGetThis();
		subClass1.callSubMethodWithGetThis();

		SubClass2 subClass2 = new SubClass2();
		subClass2.classCastException();
	}

	class BaseClass {
		void baseMethod() {
			System.out.println("BaseClass.baseMethod()");
		}

		<SubClass extends BaseClass> SubClass getThis() {
			@SuppressWarnings("unchecked")
			SubClass subClass = (SubClass) this;
			return subClass;
		}
	}

	class SubClass1 extends BaseClass {
		void subClass1Method() {
			System.out.println("SubClass1.subClass1Method()");
		}

		void callBaseMethodWithGetThis() {
			getThis().baseMethod();
		}

		void callSubMethodWithGetThis() {
			this.<SubClass1> getThis().subClass1Method();
		}
	}

	class SubClass2 extends BaseClass {
		void classCastException() {
			this.<SubClass1> getThis().subClass1Method();
		}
	}
}


Submitted On 25-MAY-2007
An important point here is that when this pattern is used for the "fluent interface"/method chaining pattern (as described in 6373386), that the JavaBean spec would need to allow non-void setters.
i.e.
public self setPropertyA() {..}

But I believe this is an important thing to have, and would have little effect on legacy code.


Submitted On 26-JUL-2007
alexsmail
This will also help in the correct implementation of the equals() method. 
[code]
class Point {
        private int x;
        private int y;
 
        public Point(int x, int y) {
                this.x = x;
                this.y = y;
        }
 
        [b]protected Object getEquivalenceClass() {
                return Point.class;
        }[/b]
        
        public boolean equals(Object o) {
                if (!(o instanceof Point))
                        return false;
                Point p = (Point)o;
                return [b]getEquivalenceClass().equals(p.getEquivalenceClass())[/b]
                        && x == p.x && y == p.y;
        }
}
 
class ColorPoint extends Point {
        private Color c;
 
        public ColorPoint(int x, int y, Color c) {
                super(x, y);
                this.c = c;
        }
 
        [b]protected Object getEquivalenceClass() {
                return ColorPoint.class;
        }[/b]
 
        public boolean equals(Object o) {
                if (!(o instanceof ColorPoint))
                        return false;
                ColorPoint cp = (ColorPoint)o;
                return super.equals(cp) && c == cp.c;
        }
}

[/code]

See http://forum.java.sun.com/thread.jspa?messageID=9791653 for more details.


Submitted On 02-AUG-2008
UlfZi
Another approach could be to implicitly allow method invocation chaining for all void methods. This would save the return statement, and its superfluous byte code. 


Submitted On 02-AUG-2008
UlfZi
What about to distinguish chainable from unchainable methods by dropping the 'void' keyword for chainables? So there would be no need to think about a new type, which is not generally usable e.g. for parameters.
OK, there would be some chance for confusion with constructors, but method names normally shouldn't start with a capital letter, but constructors should.


Submitted On 30-MAR-2009
UlfZibis
See also:
http://mail.openjdk.java.net/pipermail/coin-dev/2009-March/001180.html



PLEASE NOTE: JDK6 is formerly known as Project Mustang