Let's assume, for the moment, that the JDK contains an infinite number of interfaces in the java.lang.reflect.dispatch package. An example of these looks like this:
interface Ivoii { void fvoii(Object p1, int p2, int p3);
}
i.e. the interface has a single method and the spelling of the name of the interface tells you the name and the signature of the method (v = void, o = Object, i = int, b = byte, x = boolean, etc.)
I think these would be pretty handy for dynamic language implementers.
For example, if I was dynamically generating a MetaClass for each class I could make it implement one of these interfaces for every different message signature on the class (plus two extra Object parameters for the name of the method and the instance).
So I could compile x.toString() as
let m be the MetaClass for x
((Iooo)m).fooo("toString", x)
If I'm calling a method not on Object and I don't know the type of x i can still use the interface:
x.foo(1, 2, 3)
if (m instancof Ivooiii) { ((Ivooiii)m).fvooiii("foo", x, 1, 2, 3)
} else {
dispatch the call the slow way
}
No that for this usage to work I need to implement up to three interfaces for every call signature on the class. As the call cannot tell the type of result it wants then if foo was declared as:
int foo(int a, int b, int c)...
we would have to implement Iiooiii, Ioooiii and Ivooiii when int, a boxed int and nothing was returned in each case.
I'm not suggesting that these interfaces sit in rt.jar, of course. Ideally, the system classloader would dynamically generate them on demand. If that can't be managed then a custom classloader could do the generation.
> This is a follow on to the "avoid boxing" thread.
> Let's assume, for the moment, that the JDK contains an infinite number > of interfaces in the java.lang.reflect.dispatch package. An example of > these looks like this:
> interface Ivoii { > void fvoii(Object p1, int p2, int p3); > }
> i.e. the interface has a single method and the spelling of the name of > the interface tells you the name and the signature of the method (v = > void, o = Object, i = int, b = byte, x = boolean, etc.)
something like that was also mentioned in the Gafter Closure proposal in his Blog. Function Types or something like that did he name it.
> I think these would be pretty handy for dynamic language implementers.
I agree, it could be pretty handy, but...
> For example, if I was dynamically generating a MetaClass for each > class I could make it implement one of these interfaces for every > different message signature on the class (plus two extra Object > parameters for the name of the method and the instance).
...The major problem with code generating parts in the MetaClass I met so far is class loading. If you want to do a direct call to Foo#foo(X,Y), then you may do this:
Now the problems comes with in what classloader to place this class? Yo may or may not have access to the class loader that was used for Foo. In Groovy we had the Reflector and it was using a child to the ClassLoader in which the class was defined in. If the ClassLoader behaves normally, then nothing bad will happen. At that time we had the disadvantage of needing an interface form the Groovy lib and if two Groovy where active, then it was possible, that the normal classloading would load the wrong one, causing class cast exceptions for our Reflector, when casting the generated Reflector class to its interface. This version has the advantage of using the system loader to generate and access the interface, so there shouldn't be a problem with this.
Besides that you only need to have a classloader that returns the same class if you ask the loader for a certain class. Which means, there is still some risk involved here.
But besides that... won't this do almost the same as MethodHandles? Only that for MethodHandles you won't need to generate any classes.
[...]
> No that for this usage to work I need to implement up to three > interfaces for every call signature on the class. As the call cannot > tell the type of result it wants then if foo was declared as:
> int foo(int a, int b, int c)...
> we would have to implement Iiooiii, Ioooiii and Ivooiii when int, a > boxed int and nothing was returned in each case.
that means having method that are equal in name and parameter types. They only differ in the return type..in the same class? Now I know Java couldn't have this, but who cares about that.. so it should work, as the JVM selects by using the whole signature
> > This is a follow on to the "avoid boxing" thread.
> > Let's assume, for the moment, that the JDK contains an infinite number > > of interfaces in the java.lang.reflect.dispatch package. An example of > > these looks like this:
> > interface Ivoii { > > void fvoii(Object p1, int p2, int p3); > > } > > i.e. the interface has a single method and the spelling of the name of > > the interface tells you the name and the signature of the method (v = > > void, o = Object, i = int, b = byte, x = boolean, etc.)
> something like that was also mentioned in the Gafter Closure proposal in > his Blog. Function Types or something like that did he name it.
Yes, I think that this proposal is slighly simpler and less general.
> > I think these would be pretty handy for dynamic language implementers.
> I agree, it could be pretty handy, but...
> > For example, if I was dynamically generating a MetaClass for each > > class I could make it implement one of these interfaces for every > > different message signature on the class (plus two extra Object > > parameters for the name of the method and the instance).
> ...The major problem with code generating parts in the MetaClass I met > so far is class loading. If you want to do a direct call to > Foo#foo(X,Y), then you may do this:
> Now the problems comes with in what classloader to place this class? Yo > may or may not have access to the class loader that was used for Foo. In > Groovy we had the Reflector and it was using a child to the ClassLoader > in which the class was defined in. If the ClassLoader behaves normally, > then nothing bad will happen. At that time we had the disadvantage of > needing an interface form the Groovy lib and if two Groovy where active, > then it was possible, that the normal classloading would load the wrong > one, causing class cast exceptions for our Reflector, when casting the > generated Reflector class to its interface. This version has the > advantage of using the system loader to generate and access the > interface, so there shouldn't be a problem with this.
> Besides that you only need to have a classloader that returns the same > class if you ask the loader for a certain class. Which means, there is > still some risk involved here.
I'm not quite sure I understand this problem.
When you are creating a MetaClass you have the Class instance so you can get the classloader which loaded that class. Surely you can just use a classloader which delegates to the classloader which loaded the class to load the MetaClass?
> But besides that... won't this do almost the same as MethodHandles? Only > that for MethodHandles you won't need to generate any classes.
Yes, the advantage if this proposal is that I can implement and deploy it now (using a custom classloader and not using java.lang.reflect.dispatch, of course)
> > No that for this usage to work I need to implement up to three > > interfaces for every call signature on the class. As the call cannot > > tell the type of result it wants then if foo was declared as:
> > int foo(int a, int b, int c)...
> > we would have to implement Iiooiii, Ioooiii and Ivooiii when int, a > > boxed int and nothing was returned in each case.
> that means having method that are equal in name and parameter types. > They only differ in the return type..in the same class? Now I know Java > couldn't have this, but who cares about that.. so it should work, as the > JVM selects by using the whole signature
No, the names are always distinct int (int) -> fii Object (int) - > foi
> On 5/2/08, Jochen Theodorou <blackd...@gmx.org> wrote: [...] >> The major problem with code generating parts in the MetaClass I met >> so far is class loading. If you want to do a direct call to >> Foo#foo(X,Y), then you may do this:
>> Now the problems comes with in what classloader to place this class? Yo >> may or may not have access to the class loader that was used for Foo. In >> Groovy we had the Reflector and it was using a child to the ClassLoader >> in which the class was defined in. If the ClassLoader behaves normally, >> then nothing bad will happen. At that time we had the disadvantage of >> needing an interface form the Groovy lib and if two Groovy where active, >> then it was possible, that the normal classloading would load the wrong >> one, causing class cast exceptions for our Reflector, when casting the >> generated Reflector class to its interface. This version has the >> advantage of using the system loader to generate and access the >> interface, so there shouldn't be a problem with this.
>> Besides that you only need to have a classloader that returns the same >> class if you ask the loader for a certain class. Which means, there is >> still some risk involved here.
> I'm not quite sure I understand this problem.
> When you are creating a MetaClass you have the Class instance so you > can get the classloader which loaded that class. Surely you can just > use a classloader which delegates to the classloader which loaded the > class to load the MetaClass?
sure, you can. But when you execute your code, then it will cause the loading of several classes that are used in the parent loader. And for the method call not to end in an exception, you need to get the exact same classes from the classloader. So if the loader does not behave as a good little classloader should, then you are screwed.
>> > No that for this usage to work I need to implement up to three >> > interfaces for every call signature on the class. As the call cannot >> > tell the type of result it wants then if foo was declared as:
>> > int foo(int a, int b, int c)...
>> > we would have to implement Iiooiii, Ioooiii and Ivooiii when int, a >> > boxed int and nothing was returned in each case.
>> that means having method that are equal in name and parameter types. >> They only differ in the return type..in the same class? Now I know Java >> couldn't have this, but who cares about that.. so it should work, as the >> JVM selects by using the whole signature
> No, the names are always distinct int (int) -> fii Object (int) - > foi
>> On 5/2/08, Jochen Theodorou <blackd...@gmx.org> wrote:
> [...]
>>> The major problem with code generating parts in the MetaClass I met >>> so far is class loading. If you want to do a direct call to >>> Foo#foo(X,Y), then you may do this:
>>> Now the problems comes with in what classloader to place this class? Yo >>> may or may not have access to the class loader that was used for Foo. In >>> Groovy we had the Reflector and it was using a child to the ClassLoader >>> in which the class was defined in. If the ClassLoader behaves normally, >>> then nothing bad will happen. At that time we had the disadvantage of >>> needing an interface form the Groovy lib and if two Groovy where active, >>> then it was possible, that the normal classloading would load the wrong >>> one, causing class cast exceptions for our Reflector, when casting the >>> generated Reflector class to its interface. This version has the >>> advantage of using the system loader to generate and access the >>> interface, so there shouldn't be a problem with this.
>>> Besides that you only need to have a classloader that returns the same >>> class if you ask the loader for a certain class. Which means, there is >>> still some risk involved here.
>> I'm not quite sure I understand this problem.
>> When you are creating a MetaClass you have the Class instance so you >> can get the classloader which loaded that class. Surely you can just >> use a classloader which delegates to the classloader which loaded the >> class to load the MetaClass?
> sure, you can. But when you execute your code, then it will cause the > loading of several classes that are used in the parent loader. And for > the method call not to end in an exception, you need to get the exact > same classes from the classloader. So if the loader does not behave as a > good little classloader should, then you are screwed.
> [...]
You need a classloader which is able to create your interfaces AND be able to load the classes used by the code. It's not a big deal if the user code follows the parent loader delagation scheme, you can change the application classloader and user defined classloaders will use it as parent.
The trouble comes if the user use a classloader that doesn't follow the scheme. In my opinion, there is currently no way to work around that because the only solution i see is to be able to load interfaces using the boot classloader.
Else, the DaVinci AnonymousClassLoader is able to patch the constant pool of a class. This allow to reuse the same bytecode for all interfaces and just patch the method signature to replace it by the one you need. It doesn't solve the classloader problem above but it avoid to generate bytecode arrays at runtime for each interfaces.
>>> > No that for this usage to work I need to implement up to three >>> > interfaces for every call signature on the class. As the call cannot >>> > tell the type of result it wants then if foo was declared as:
>>> > int foo(int a, int b, int c)...
>>> > we would have to implement Iiooiii, Ioooiii and Ivooiii when int, a >>> > boxed int and nothing was returned in each case.
>>> that means having method that are equal in name and parameter types. >>> They only differ in the return type..in the same class? Now I know Java >>> couldn't have this, but who cares about that.. so it should work, as the >>> JVM selects by using the whole signature
>> No, the names are always distinct int (int) -> fii Object (int) - > foi
> >> On 5/2/08, Jochen Theodorou <blackd...@gmx.org> wrote:
> > [...]
> >>> The major problem with code generating parts in the MetaClass I met > >>> so far is class loading. If you want to do a direct call to > >>> Foo#foo(X,Y), then you may do this:
> >>> Now the problems comes with in what classloader to place this class? Yo > >>> may or may not have access to the class loader that was used for Foo. In > >>> Groovy we had the Reflector and it was using a child to the ClassLoader > >>> in which the class was defined in. If the ClassLoader behaves normally, > >>> then nothing bad will happen. At that time we had the disadvantage of > >>> needing an interface form the Groovy lib and if two Groovy where active, > >>> then it was possible, that the normal classloading would load the wrong > >>> one, causing class cast exceptions for our Reflector, when casting the > >>> generated Reflector class to its interface. This version has the > >>> advantage of using the system loader to generate and access the > >>> interface, so there shouldn't be a problem with this.
> >>> Besides that you only need to have a classloader that returns the same > >>> class if you ask the loader for a certain class. Which means, there is > >>> still some risk involved here.
> >> I'm not quite sure I understand this problem.
> >> When you are creating a MetaClass you have the Class instance so you > >> can get the classloader which loaded that class. Surely you can just > >> use a classloader which delegates to the classloader which loaded the > >> class to load the MetaClass?
> > sure, you can. But when you execute your code, then it will cause the > > loading of several classes that are used in the parent loader. And for > > the method call not to end in an exception, you need to get the exact > > same classes from the classloader. So if the loader does not behave as a > > good little classloader should, then you are screwed.
> > [...]
> You need a classloader which is able to create your interfaces AND > be able to load the classes used by the code. > It's not a big deal if the user code follows the parent loader > delagation scheme, > you can change the application classloader and user defined classloaders > will use it as parent.
> The trouble comes if the user use a classloader that doesn't follow the > scheme. > In my opinion, there is currently no way to work around that because > the only solution i see is to be able to load interfaces using the boot > classloader.
That's a good point, however consider this:
These interfaces are in a package that contains no other classes or interfaces and the package *never* appears in the classpath.
It's therefor safe for the classloader which loads the MetaClass to delegate requests for thinks in this one package to the classloader which generates them on the fly and to delegate all other requests to the classloader which loaded the class.