Trouble inferring type of lambda

Howard Lovatt howard.lovatt at gmail.com
Sun Aug 22 22:31:09 PDT 2010


Hi Maurizio,

As a bit of background I was thinking of giving a talk at the Sydney
JUG, nothing arranged yet - just a thought, on the likely Java 7
features, hence the writing style of the code below. All the examples
I am having trouble with, except
String.String.CASE_INSENSITIVE_ORDER.compare( String, String ) - which
is obvious anyway, are covered in the code below. Hence this one email
covers all. I have also attached the files and the compile/run script.

public interface Method1<R, A1, throws E> { public R call( A1 a1 ) throws E; }

public interface SortableList<T extends Comparable<? super T>> extends List<T> {
  extension void sort() default Collections.sort;

  <throws E> extension void forEach( Method1<T, T, E> method ) throws
E default Trait.forEach;

  static class Trait {
    public static <T extends Comparable<? super T>, throws E> void forEach(
           final SortableList<T> self, final Method1<T, T, E> method )
throws E {
      for ( int i = 0; i < self.size(); i++ ) {
        final T oldValue = self.get( i );
        final T newValue = method.call( oldValue );
        self.set( i, newValue );
      }
    }
  }
}

public class IntList11 extends AbstractList<Integer> implements
SortableList<Integer> {
  private final int[] values = new int[] { 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0 };

  @Override public Integer get( final int index ) { return values[ index ]; }

  @Override public Integer set( final int index, final Integer newValue ) {
    final int old = values[ index ];
    values[ index ] = newValue;
    return old;
  }

  @Override public int size() { return values.length; }

  @Override public <throws E> void forEach( final Method1<Integer,
Integer, E> method ) throws E {
//    for ( int i = 0; i < size(); i++ ) {
    for ( int i = 0; i < values.length; i++ ) {
//      final Integer oldValue = get( i );
      final Integer oldValue = values[ i ];
      final Integer newValue = method.call( oldValue );
//      set( i, newValue );
      values[ i ] = newValue;
    }
  }
}

public class Main {
  public static void main( final String... notUsed ) throws Throwable {
    // coin-dev
    // TODO
    // lambda-dev
    lambdas();
//    extensionMethods(); - no runtime at present
    exceptionTransparency();
    // mlvm-dev
    // TODO
  }

  private static void lambdas() throws Throwable {
    // SAM conversion, shorthand for an instance of an anonymous inner class
    // Syntax may change to { args -> body }
    // final Runnable r1 = new Runnable() {
    //   public void run() { out.println( "Start" ); }
    // };
    final Runnable r1 = #() { out.println( "Start" ) };
    r1.run();

    // Can have complex bodies as well as 'expressions', seperated by
; and ; on last line
    // See below for alternative
    final Runnable r2 = #() {
      int sum = 0;
      for ( int i = 1; i <= 4; i++) { sum += i; }
      out.println( "Sum 4 = " + sum );
    };
    r2.run();

    // Can be an abstract class
    abstract class AbstractRun implements Runnable {
      AbstractRun() { throw new NullPointerException(); }
    }
    try {
      final AbstractRun r3 = #() { out.println( "Never called" ) };
      r3.run();
    } catch ( final NullPointerException notUsed ) {
      out.println( "Exception in constructor" );
    }

    // Arguments and Target Typing
    // Argument type is ActionEvent
    final ActionListener al1 = #( notUsed ) { out.println(
"ActionListener lambda 1 called" ) };
    final JButton b1 = new JButton();
    b1.addActionListener( al1 );
    b1.doClick();

    // Can type arguments but not return type, little point though - see below
    final ActionListener al2 = #( final ActionEvent notUsed ) {
      out.println( "ActionListener lambda 2 called" )
    };
    b1.addActionListener( al2 );
    b1.doClick();

    // More usefully you can add final.
    final ActionListener al3 = #( final notUsed ) {
      out.println( "ActionListener lambda 3 called" )
    };

    // Method References, syntax like Javadoc
    b1.addActionListener( Main#print( ActionEvent ) );
    b1.doClick();

    // Can be bound to an object
    class Print {
      void print( final ActionEvent notUsed ) { out.println(
"Main.Print.print method called" ); }
    }
    b1.addActionListener( new Print()#print( ActionEvent ) );
    b1.doClick();

    // this
    out.println( "Class = " + al3.getClass() +
            ", instanceof ActionListener = " + (al3 instanceof ActionListener) +
            ", instance of enclosing class (Main) = " + (al3 instanceof Main) );

    // Effectively final
    // No use to me, but others like it!
    String s = "Effectively final"; // not *declared* final, but
effectively final
    final Callable<String> cs = #() { s };
    out.println( cs.call() );
  }

  private static void print( final ActionEvent notUsed ) {
    out.println( "Main.print method called" );
  }

  private static void extensionMethods() {
    final IntList11 il = new IntList11();
    out.println( il );
    il.sort();
    out.println( il );
  }

  private static void exceptionTransparency() {
    final IntList11 il = new IntList11();
    out.println( il );
//    il.forEach( #( i ) { 2 * i } ); // No exception; no try block -
has syntax error
    il.forEach( #( i ) { return 2 * i; } ); // No exception, no try block
    out.println( il );
//    try {
      il.forEach( #( i ) {
        if ( i < 3 ) { throw new Exception(); }
        return i * i;
      } ); // Should need to catch checked exception!
//    } catch (final Throwable notUsed) {
//      out.println( "Exception caught" );
//    }
    out.println( il );
  }
}

Keep up the good work,

 -- Howard.

On 23 August 2010 03:45, maurizio cimadamore
<maurizio.cimadamore at oracle.com> wrote:
> On 22/08/2010 07:09, Howard Lovatt wrote:
>>
>> For:
>>
>>   public interface Method1<R, A1, throws E>  { public R call( A1 a1 )
>> throws E; }
>>
>> and:
>>
>>   public<throws E>  void forEach( final Method1<Integer, Integer, E>
>> method ) throws E { ... }
>>
>> The compiler has trouble with:
>>
>>    il.forEach( #( i ) { throw new Exception(); } ); // Need to catch
>> checked exception
>>
>> Giving:
>>
>> lambdas/Main.java:34: method forEach in class IntList11 cannot be
>> applied to given types
>>       il.forEach( #( i ) { throw new Exception(); } ); // Need to
>> catch checked exception
>>         ^
>>   required: Method1<Integer,Integer,E>
>>   found: #void(?)(Exception)
>>   where E is a type-variable:
>>     E extends Exception declared in method
>> <E>forEach(Method1<Integer,Integer,E>)
>>
>> Qualifying doesn't help:
>>
>>   Method1<Integer, Integer, Exception>  #( i ) { throw new Exception(); }
>>
>> It gives:
>>
>> lambdas/Main.java:34: incompatible types; no instance(s) of type
>> variable(s) ? exist so that #void(?)(Exception) conforms to
>> Method1<Integer,Integer,Exception>
>>       il.forEach( Method1<Integer, Integer, Exception>  #( i ) { throw
>> new Exception(); } ); // Need to catch checked exception
>>                   ^
>>   required: Method1<Integer,Integer,Exception>
>>   found:    #void(?)(Exception)
>>
>> Is the problem that the return type isn't expressible? It isn't really
>> void, it is 'NeverReturns'.
>>
>
> Uhmm the problem here seems more related with a failure in inference of the
> lambda parameter (the '?' that you are seeing). Again it would be helpful to
> see the declaration of the receiver class as well as the type of 'il'.
>
> Maurizio
>>
>>   -- Howard.


More information about the lambda-dev mailing list