Lambda and JSR 292 method handle

Neal Gafter neal at gafter.com
Wed Dec 30 07:58:13 PST 2009


On Tue, Dec 29, 2009 at 11:32 PM, Howard Lovatt <howard.lovatt at iee.org>wrote:

> Neal,
>
> Good points, the first:
>
>
> >
>
> > List<? *extends* #String(Object)>
> >
>
>
> > to a value of type
> >
>
> > List<? *extends* #Object(String)>
> >
>
>
>
> Is easily fixable by having the reified versions extend the generic
> versions with a special case for primitives, i.e.:
>
> *public* *abstract* *class* Callable$Int *implements* Callable$0<Integer> {
>   *public* *abstract* *int* callInt();
>   @Override *public* *final* Integer call() { *return* callInt(); }}
>
> That answer is nonresponsive to my question.


> > Also, there need to be subtype relations in both
> > directions between your Callable$0<String> and
> > Callable$String but that is impossible because they are
> > distinct interfaces. If you try to provide the subtype
> > relations in just one direction, things quicky get out of
> > hand (i.e. an exponential explosion in direct
> > superinterfaces of the generated interfaces) when there
> > are multiple lambda arguments.
>
> The above modification to implement Callable$... solves this problem in
> one direction and the other is via 'cast' methods. The idea was that the
> 'cast' methods are loader generated, though re-reading my post I didn't make
> this clear (sorry).
>

My point is that the subtypes in one direction generate an inheritance
hierarchy that gets out of hand, and the cast methods in the other direction
don't actually work.

To take a specific simple example of the latter issue, consider a method
that returns a generic list of functions:

*<T> List<#T()> lazify(List<T> data) {
    List<#T()> result = new ArrayList<#T()>();
    for (T t : data) result.add(#()t); // adds element of type Callable$0<T>
    return result;
}
*

the list that is returned contains lambdas of type Callable$0<T>.  Then we
call it on some data

*List<#String()> alphabet() {
    return lazify(**Arrays.asList("a", "b", "c")**);
}
List<#String()> **alphabet **= **alphabet**();*

now alphabet contains a List whose elements are of type Callable$0<String>
(but the compiler probably thinks those elements are of type
Callable$String).  So we pull a datum out of it.

*#String() firstLetter = **alphabet**.get(0);
*

Now we've assigned something of type Callable$0<String> to something of type
Callable$String.  Where in the execution of this code did the "cast" occur?

I am making the assumption that these 'casts' are rare and therefore in
> practice you won't get an explosion of 'cast' methods.
>

As much as I take issue with your assumption, I am more concerned about
correctness than performance.

-Neal


More information about the lambda-dev mailing list