Notes on implementing concise calls to constructors with type parameters

Howard Lovatt howard.lovatt at
Thu May 21 05:18:07 PDT 2009

Hi Peter,

2009/5/21 Peter Levart <peter.levart at>:
> Hello Howard,
> What Neal and others are trying to point out is that your "textual
> substitution algorithm" is not defined. The name "textual" implies that it
> should be simple. But the right thing to do is not simple at all.

I suspect that we have more of a philosophical difference rather than
a technical one. I think it is a mistake to choose complicated systems
that few understand; you have to keep it simple. Much of Java is a
simplification of C++ and this simplification is the reason for the
success of Java. An example of a feature of Java that has received
much negative comment is variance, to me this is an example of a
system that though powerful is too complicated. The reason for people
wanting to have type declarations on the left rather than the var
(auto) type construct is for this very reason of simplicity, so it
makes no sense to me to use a complicated system when the aim is
simplicity. In summary the number one goal for me is simplicity,
rather than ultimate power.

It doesn't matter how hard you try with type inference it would seem
that some part of it will fail. The following example from Peter Ahe
blog demonstrates this:

  static <T> void merge( List<T> l1, List<T> l2 ) {}

  static void test(List<? extends Object> list) { merge(list, list); }

Fails with an obscure error message:

<T>merge(java.util.List<T>,java.util.List<T>) in listtypesafety.Main
cannot be applied to (java.util.List<capture of ? extends
java.lang.Object>,java.util.List<capture of ? extends

Yet to a human reader it is obvious that it is type sound. Now
unfortunately you have a failure for no apparent reason and a system
that is so complicated you cannot work out why and therefore can't
work out how to fix the problem. (I do know why it fails, but you have
to admit it is not obvious.)

> Have you
> looked at the 3rd JLS section ?


> To just scratch the surface, take
> the following example:
> public interface IntA<X, Y> { ... }
> public class ClsA<Z> implements IntA<String, Z> { ... }
> public class ClsB<Z> implements IntA<Z, Integer> { ... }
> ...
> public void doIt(IntA<String, Integer> param) { ... }
> ...
> // what should "textual substitution" do in the following 2 cases:
> anInstance.doIt(new ClsA());
> // vs.
> anInstance.doIt(new ClsB());

For an example like this I would use raw types, to remain compatible
with existing code. This is the same answer I gave for multiply
constrained types.

Also note the following slight variation currently fails:

  static class ClsA<Z> implements IntA<String, Z> {
    static <Z> ClsA<Z> instance() { return new ClsA<Z>(); }

  static class ClsB<Z> implements IntA<Z, Integer> {
    static <Z> ClsB<Z> instance() { return new ClsB<Z>(); }

  static void inferenceTest() {
    doIt( ClsA.instance() );
    doIt( ClsB.instance() );

Which shows what a difficult example this is.

Back on my philosophical point, I don't mind the inference resulting
in a raw type (no inference) for an example like this. The chance of
something like this occurring in real code is slim and if you are
really worried about the types then you can specify them. For me it is
much more important that examples like:

    // Translation                                       // Original
    Ex              e___ = new Ex();              // Ex
e___ = new();
    Ex              e__s = new Ex<String>(); // Ex               e__s
= new<String>();
    Ex              e_e_ = new Ex();              // Ex
e_e_ = new Ex();
    Ex              e_es = new Ex<String>(); // Ex               e_es
= new Ex<String>();
    Ex<String> es__ = new Ex<String>(); // Ex<String> es__ = new();
    Ex<String> es_s = new Ex<String>(); // Ex<String> es_s = new<String>();
    Ex<String> ese_ = new Ex<String>(); // Ex<String> ese_ = new Ex();
    Ex<String> eses = new Ex<String>(); // Ex<String> eses = new Ex<String>();

Work well and are easily understood.


 -- Howard.

> Peter.
> On Mon, May 18, 2009 at 10:13 AM, Howard Lovatt <howard.lovatt at>
> wrote:
>> Hi Neal,
>> Yes I should have spelled this out, it is one of those things obvious
>> to the author but not to the reader. I would propose that given more
>> than one method of the same name, method in example below, with the
>> general declaration for each following the syntax:
>> ... method ( typeLHS [<genericParametersLHS>] name , ... ) { ... }
>> and given the call:
>> ... method ( new [typeRHS] [<genericParametersRHS>] ( ... ) , ... );
>> Then a three step procedure would be used:
>> 1. If typeRHS is absent assume for step 2 type Void, where Void is the
>> bottom type (in Java 7 this may be called Null but I chose Void to be
>> consistent with the InvokeDynamic proposal)
>> 2. Resolve method as normal and hence find typeLHS and if specified
>> genericParametersLHS also
>> 3. Apply textual substitution algorithm, i.e. If typeRHS is absent
>> substitute typeLHS and if genericParametersRHS is absent and
>> genericParametersLHS is present then substitute genericParametersLHS
>> For example, given two methods:
>> void method( Object notUsed ) { out.println( "Object" );  }
>> void method( String notUsed ) { out.println( "String" );  }
>> The call:
>> method( new() );
>> would print String because it would be translated by the textual
>> substitution algorithm into method( new String() ), i.e. the same
>> behaviour as method( null ) because null has type Void (bottom).
>> Does that add sufficient clarity? I would be really interested if you
>> can see a problem with the technique?
>> If not the method maybe a good solution as it has many desirable
>> characteristics (as listed in previous posts in this thread). I also
>> note that many people would like a var or auto style declaration and
>> maybe this proposal of text substitution can satisfy more people than
>> other proposals, since it retains LHS types but saves re-specification
>> of type, generic type, and doesn't require a diamond operator on the
>> RHS.
>>  -- Howard.
> ______________________________________________________________________
> This email has been scanned by the MessageLabs Email Security System.
> For more information please visit
> ______________________________________________________________________

  -- Howard.

More information about the coin-dev mailing list