My colleague Colin Walters has recently been working on automatically
generating language bindings from the Java to C libraries based on the
GObject system. (See http://live.gnome.org/JGIR.) One question that we
were interested in is how well things would work for non-Java
languages on the JVM. So, I spent some time yesterday trying it out
with Rhino. It basically worked out of the box:

 
http://svn.gnome.org/viewvc/java-gobject-introspection/trunk/gtktest.js?view=markup

Cool! But there was one aspect of the binding that I wasn't very happy
with - how you connect to GObject "signals" (callbacks) ... so I
wanted to throw out some ideas for small Rhino enhancements to make
that better.

In Java, the way you make a connection to a signal in JGIR (as in the
existing Java GNOME hand-written bindings for the same libraries)
looks like:

 button.connect(new Button.Clicked() {
     public void onClicked() {
         System.out.println("I was clicked");
     }
 });

So it uses overloading on the passed in interface to tell which signal
to connect to. This translates over to:

  button.connect(Button.Clicked({
            onClicked: function () {
                print("I was clicked");
            }}));

Which isn't bad, but there's a lot of extra noise there. One idea I
had was that this could be simplified if Rhino allowed passing a
function rather than an object when building an interface if with a
single method, so:

  button.connect(Button.Clicked(
         function () {
            print("I was clicked");
         }));

Removing some of the excess noise. This seems like something that
would be highly compatible with existing programs and convenient in
any case where you had an overload on one-function interfaces (I think
there are standard Java methods that take either Callable or Runnable)

The other possibility would be to extend JGIR a little bit to have a
second way of connecting signals generically avoiding the overload, so
there was:

  interface Invokable {
     Object invoke(Object[] args);
  }

  public long connect(String signalName, Invokable callback);

Then you could *almost* use the existing Rhino function => single
function interface mapping. It doesn't quite work because the Object[]
will get mapped to an array. You would need to do:

  widget.connect("MouseDown", function(args) {
     print(args[0].x, args[0].y); // args[0] is the event object
  });

My first thought was, what if Rhino automatically "de-boxed" a method
with a single Object[] argument? It's not crazy behavior, but it's a
little magic, and maybe not compatible enough. The second thought was
that varargs methods are actually flagged in the bytecode. So, if we
modified Invokable a bit to have:

  interface Invokable {
     Object invoke(Object args...);
  }

And Rhino automatically turned Java varargs into the Javascript
concept of calling with varargs (the argument list is just a list of
arguments), then everything would work out perfectly.

  widget.connect("MouseDown", function(event) {
     print(event.x, event.y);
  });

Only disadvantages I see: there might be a few programs out there
depending on the current behavior, and maybe it's a little weird to
make the mapping depend on something that is not, strictly speaking,
part of the method signature.

Reactions to either of the above? Other ideas?

- Owen
_______________________________________________
dev-tech-js-engine-rhino mailing list
[email protected]
https://lists.mozilla.org/listinfo/dev-tech-js-engine-rhino

Reply via email to