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