[Java] Function Binding Redux (long post)
John Moeller <[email protected]>
| Newsgroups | gmane.comp.lib.boost.langbinding |
|---|---|
| Message-ID | <[email protected]> |
Okay. So I've been spending the last few weeks attempting to figure out
how one would use a "natural" syntax to make a function call in the Java
Langbinding, that is, if you have a Langbinding class "X" and a function
"f" defined as a member, how can you write code such as this:
X x = new X(...);
...
SomeClass sc = x.f(y, z, 42);
The short answer seems to be "not easily." At the very least, at the
center of any solution needs to be some kind of function dispatcher on
the Java side that will take in the arguments, pass them to the
Langbinding module, and get the return. Whether it's as simple as:
public <ReturnValue> ReturnValue call(Object ... args) { ... }
or something involving more encapsulation, something akin to this needs
to dispatch the function call.
So here's the solutions so far:
1. Use the function dispatcher directly.
This is ok, but not great, and it's certainly a step away from natural.
It's at least not entirely procedural, because you can define a
wrapper object and make a call on it:
import boost.langbinding.Instance;
...
Instance x = new Instance("X", arg1, arg2, arg3);
x.call("f", arg4, arg5);
2a. Generate a Java source file where the methods wrap the function
dispatcher.
Not entirely appealing, because it's a build-time solution, not a
runtime solution. But it would enable the use of "natural" syntax very
easily.
2b. Generate the same, except directly in bytecode, and put the result
in a class file.
Same advantages as (2a), except without the compile time, but the
drawback that we'd have to maintain bytecode generation (probably not a
big deal, though).
3. Do the same as (2b), but load the class at runtime with a special
class loader. This is (from what I understand) the crux of Rene's idea,
and the most initially appealing.
I've been trying to think of ways to make this work, but there are some
major compromises:
1. Without wrangling class loaders at startup, it's impossible to use
the class name in source code without it having been loaded first.
This means that you have to load the class, then use it through
its Class interface. This means using reflection, which is an
entirely procedural API. It's pretty gross. If the class can
implement an interface though, (I'm referring to the Java kind of
interface), then you could just cast it, because a class can
implement an interface that's already been loaded by another class
loader with no problem.
2. You could wrangle class loaders at startup, or some major
milestone in your program's execution. That is, you could come up
with a "launcher" that set up the class loader chain, and invoke
"main" from your main app class. This would enable you to use
your generated classes naturally, because the main class would be
loaded with the special class loader in the loader chain, and all
of its dependent classes (i.e., the rest of the program) would be
loaded with the same loader chain.
Unfortunately, this means that you can't have your app classes
visible from the launcher's classpath. You actually have to take
steps to *prevent* the default loaders from finding your app
classes. This is inconvenient, and may simply be impossible for
some users. They may not have control over how their classes are
started.
3. Hack the JVM startup so that it uses a different class loader.
This still has the problem of accessibility, and probably the
problem of portability, because not all JVMs may implement an app
class loader override.
I thought of another alternative. If we're willing to compromise on
natural syntax, we can go one better than compromise (1) above. I got
this idea from looking at the Java scripting API. In the scripting API,
you can pass an interface class to your script object, and have it
return an object defined in the script as an instance of the interface.
We could do something like this:
Instance x = new Instance("X", ctorArg1, ctorArg2);
Runnable r = x.asInterface(Runnable.class);
new Thread(r).start();
or even:
WrappedClass x = new WrappedClass("X");
Runnable r = x.asInterface(Runnable.class, ctorArg1, ctorArg2);
new Thread(r).start();
This would presumably throw an exception if there wasn't a function void
run() that could be dispatched to.
It seems that it should be possible to generate a class that implements
an interface on the fly (I think that implemented interfaces are just
markers in the class data anyway).
What do you think?
--
John Moeller
[email protected]
-------------------------------------------------------------------------
This SF.net email is sponsored by: Microsoft
Defy all challenges. Microsoft(R) Visual Studio 2005.
http://clk.atdmt.com/MRT/go/vse0120000070mrt/direct/01/