Function types versus arrays (reification using interface injection)
Peter Levart
peter.levart at gmail.com
Mon Feb 8 15:05:48 PST 2010
On Monday 08 February 2010 20:30:42 Alex Buckley wrote:
> Neal raises a fair point. I recognize that arrays of function types are
> as potentially unsafe at runtime as arrays of non-wildcard parameterized
> types.
>
> And this is the same problem one sees when passing variables of
> parameterized types as varargs parameters. The varargs method body can
> silently do unsafe things, thanks to Object being a universal supertype.
>
> Banning arrays of function types is an option. It somewhat conflicts
> with Project Coin's promotion of [] syntax to read/write collections.
>
> I am interested in people's thoughts on the limitations of arrays of
> parameterized types. (Reification was not and is not an option, so
> please no ranting about the stupid implications of erasure.) Does anyone
> care about arrays anymore?
Hello Alex,
Did you mean "Reification was not and is not an option" for general case of generic types or did
you mean it is not an option "just for function types" too?
I don't know, maybe this idea will sound stupid, but I'll try anyway...
If you implement function types as interfaces, then function types that take just primitive
parameters and have primitive return type are already reified aren't they?
When a function type takes a reference type parameter and/or has a reference return type, then
some proposals represented it as a generic interface which is represented in run-time as an
interface with erased parameter/return types - such function type is not reified.
Why not treat function types with reference type parameters and/or return type the same as
function types with primitive only parameters and return type? Because of sub-type relationships
among function types? Read on...
What we're trying to achieve is that following would be possible:
#String(Object) func1 = #(Object o)(o == null ? "null" : o.toString());
#Object(String) func2 = func1;
If the two function types above were represented as the following two interfaces (respectively):
public interface FuncObjectToString {
String invoke(Object param);
}
public interface FuncStringToObject {
Object invoke(String param);
}
Then the javac compiler could, for the lambda expression above, generate a class that would
implement interface FuncObjectToString:
public class LambdaImpl implements FuncObjectToString { ... }
JVM's classloader would have to maintain a registry of all function type interfaces and
implementations (lambda classes). Each time a new function type or lambda implementation class
is loaded, JVM would consolidate implementation classes by "injecting" function interfaces into
them and generating "bridge" methods
(http://blogs.sun.com/jrose/entry/interface_injection_in_the_vm).
In the above example, if FuncObjectToString and LambdaImpl were already loaded after the
following line was executed:
#String(Object) func1 = #(Object o)(o == null ? "null" : o.toString());
which is just a translation of:
FuncObjectToString func1 = new LambdaImpl();
and the next line is about to be executed:
#Object(String) func2 = func1;
which is just a translation of:
FuncStringToObject func2 = (FuncStringToObject) func1;
Then JVM would proceed by "lazy" loading of interface FuncStringToObject which would trigger
injecting this interface into all registered lambda classes that are "by definition" subtypes of
FuncStringToObject. It's invoke method would be "implemented" as a "bridge" method invoking
lambda's main invoke method. So after FuncStringToObject is loaded LambdaImpl would be
implementing an additional interface "FuncStringToObject" so a cast occuring after that point
would succeed.
This would "reify" function types as much as possible. Not totally, since the following two
types for example:
#List<Object>() and #List<String>()
would still be represented by the same interface at runtime.
Also this would by default return incorrect result:
#Object(String).class.isAssignableFrom(#String(Object).class)
But it could be made to return correct result.
Is this to lunatic? Am I missing a bunch of problems possible with this approach?
Regards, Peter
>
> Alex
>
> Rémi Forax wrote:
> > Le 07/02/2010 19:41, Neal Gafter a écrit :
> >> I've been asked if arrays and function types will play nicely
> >> together. Specifically, for example, whether or not something like
> >> the following will be allowed:
> >>
> >> #String(String)[] arrayOfFunction = new #String(String)[10];
> >>
> >> The current draft spec, by the absence of any constraining rules,
> >> implies yes. But if I have to guess, I would say the end result of
> >> project lambda will probably say no. Although we haven't talked much
> >> about implementation techniques, I'm not aware of any proposed
> >> implementation technique that would allow this without opening a hole
> >> in the type system.
> >>
> >> I don't know whether we should consider this important or not (I
> >> don't; I'm perfectly happy using java.util.List), but if it is
> >> important then someone should be thinking about what needs to happen
> >> (VM support?) to make it work.
> >
> > For the record the problem is:
> >
> > #String(String)[] arrayOfFunction = new #String(String)[10];
> > Object[] array = arrayOfFunction;
> > array[0] = #int() (2);
> >
> > The last line should raise an array store exception.
> > So the VM should be aware of the precise type of the array of function.
> >
> > Currently, neither the anonymous class translation nor the method handle
> > one provide reified function type so array of function types are unsafe.
> >
> > Because function type doesn't exist in the language, I propose to make
> > the syntax
> > for an array of function type (#String(String)[]) illegal.
> >
> > I'm also happy with List, perhaps we should introduce a new interface
> > ReadOnlyList
> > which is a super type of List and array of objects but that another
> > story.
> >
> >> Cheers,
> >> Neal
> >
> > Rémi
>
More information about the lambda-dev
mailing list