Re: Java support in GTK/Gnome



per,

your email carried a From: Tim Janik line for me, eventhough it should
probably have originated from per@bothner.com?

On 18 Aug 2000, per@bothner.com wrote:

> Tim Janik <timj@gtk.org> writes:
> > i feel some more thoughtfull
> > discussion from both parts needs to happen before we come up with a good
> > solution. if you could forward this email, that'd be apprechiated.
> 
> That was my hope with the document.  As should be clear, my expertise is
> in Java, not Gtk, so I hope Gtk/Gnome developers would use my ideas as a
> starting point (as Oskar has).  (Btw:  I have discussed these idea with
> Miguel, and he seems to be quite favorable.  He suggested the idea of
> merging the Gtk and Java objects using CNI, but said the idea had met
> opposition in the past.  I hope my "embedding" version of the idea
> will have less opossition.)

yeah, i had miguel mentioning that idea to me earlier, but on second
thought, it's just bothering about a few additional bytes per object<->proxy
connection, while at the same time enforcing it makes proxy overhead mandatory
for every GObject, even those that Java doesn't really have to/want to deal with.

> > on the signal part, dealing with interfaces ala:
> > 
> > public ButtonClickedListener
> > {
> >   public void clicked ();
> > }
> > public class Button extends Bin
> > {
> >   ...
> >   public native void addClickedListener(ButtonClickedListener listener);
> >   public native void removeClickedListener(ButtonClickedListener listener);
> > }
> > ...
> > will become quite cumbersome since you have the additonal overhead
> > of add<SIGNAL>Listener remove<SIGNAL>Listener for ever signal on all
> > objects,
> 
> I don't understand this point.  You don't get the "additonal overhead"
> on "all objects".  You get appropriate methods defined in appropriate
> classes.  There is no per-object overhead beyond that needed by the
> existing gtk_signal_connect mechanism.

you've got extra API function overhead for every class that introduces a
signal of which tehre are quite a bunch. and for every one of them, you'll
at least need variants for add*Listener, remove*Listener, block*Listener and
unblock*Listener.
while you can certainly do that, and prolly the one good reason here is type
safety, you will have to still work on a generic interface for dynamically
added signals (much more so once GType interfaces can introduce signals), so
i personally would rather focus on making that generic part as convenient
and flexible as possible.

> > and you don't support dynamically adding signals to existing
> > classes this way.
> 
> True, but I'm not saying this is the *only* way to add signals - only
> the one that would be recommended.  I think the extra type safety is 
> good.
> 
> > moving to something that'd allow button.connect ("clicked", listener);
> > seems far more appealing.
> 
> That would still be possible.  However, invoke a addClickedListener
> method is more natural to Java programmers (it is the standard way
> events are handled in Java), so I think people would prefer it,
> especially since you also get compile-time type checking.
> 
> > though, then he writes (and that's the idea you seem to consider most
> > appealing):
> > 
> > | However, there is a trick we can use, inspired by C++ multiple inheritance:
> > | We embed the Gtk object in a Java Object.
> > [...]
> > | Note that a Gtk object has no fields that can be accessed from Java. All
> > | fields have to be accessed using methods that are written in
> > | native (C or C++) code. 
> > [...]
> > | When we create a Gtk instance, we now we actually want to do is create te
> > | Java wrapper instance. For example, we want gtk_button_new() to be
> > | equivalent to:
> > |  (GtkWidget*) ((char*) new gnu::gtk::Button() + JAVA_OFFSET)
> > 
> > which does add the extra memory overhead to each GObject unconditionally.
> 
> Yes, but only a few words:  The Java Object header.  Let us say that is
> two words.  (It depends on which implementation tricks/tradeoffs you use.)
> Many malloc implementations also have a two-word-per-object overhead.
> So the per-object memory overhead is implementation-dependent and hard to
> quantify, but in any case it is relatively small.  It is certainly less
> than the overhead you would get by using a separate Java proxy object.
> Which would dominate depends on how may of your objects would need to
> be accessed from Java - but this would be difficult to manage.

yeah, but to gain 4 or 8 "wasted" bytes per proxy used by the actuall
java program, you pay extra proxy overhead for every GdkWindow, pixmap,
widget style etc etc being created, not to mention the bunch of unexposed
widgets ala notebook labels, composite children and so forth.
to make a quick estimate, i roughly guess you end up with at least two
extra uneeded proxies per widget in an application. that's being made up based
on the extra GdkWindow plus its GdkWindowImpl object for all !NO_WINDOW widgets
which are usually unused by apps, and to compensate for the NO_WINDOW widgets,
add up things like colors pixmaps, images, widgets with more than one Gdkwindow,
styles etc. ;)
furtherly considering that- especially for composite widgets -not all of
the widgets are going to be directly adressed by java functions, it's
pretty evident to me that your embedding idea creates a huge bunch of
overhead even for intimidating complex apps that shuffle around a lot
with widget sytem internals. you might want to talk to some of the other
language binders we have around, afaik all of them use on-demand-proxy
creation.

> Let me emphasize that the Java Object header would only by added to
> Gtk objects *if* the mem_alloc_callback is non-null and allocates a
> Java object - i.e. only in Java/Gtk applications.

yep, that's pretty obvious. i hardly see the java bindings adding
allocation overhead to non-java-bound applications ;)

> > i don't think physical object embedding will provide you with any significant
> > advantages though. a much more viable alternative is probably to stick to
> > your java proxy approach and use something like (also pseudo code of course ;):
> > ...
> > JProxy*
> > gobject_get_jproxy (GObject *object)
> > {
> >   JProxy *jproxy = NULL;
> >   if (object)
> >     {
> >       jproxy = g_object_get_data (object, "java-proxy");
> >       if (!jproxy)
> >         {
> >           jproxy = jproxy_new_gobject (object);
> >       
> >           g_object_set_data_full (object, "java-proxy",
> >                                   jproxy, jproxy_gobject_died);
> >         }
> >     }
> >   return jproxy;
> > }
> > ...
> > however, with keeping java object proxies and creating them on demand,
> > you don't pay unecessary memory penalties per GObject,
> 
> However, the memory penalty for usin proxies is much bigger, plus
> the time cost of mapping between a Java proxy and the GObject is
> much bigger.  How significant these are depends on how many objects
> need to access from Java.

the time costs, i'd guess, will be pretty insignificant.
for java->gobject it'll be a pure pointer field readout of
your implementation structures, and for gobject->proxy lookups,
you can use object_set/get_data indexed by quarks (similar to XAtoms,
GQuarks are global integer ids assigned to strings) which will in
2.0 boil down to a binary search through all the object data items
installed on that gobject (i.e. O(log2(n_data_items))).

> One issue is garbage collection:  Each of the Java proxies has to be
> registered as a "root", so it doesn't go away until the GObject goes
> away *and* and references from Java go away.  This adds more overhead.

if you use dynamic proxies, you may even destroy those once java
references go away, release you gobject reference with that and
let the gobject live on, maintained by glib/gtk then. if it's later
rereferenced like say through contain.get_children(), you could
recreate the proxy. i'd think you can be way more memory efficient
with this approach.

> > also, at least at the object level, several language bindings can live
> > in the same adress space, say i have an application that provides GObject's
> > (not necessarily widgets) and want to provide scripting abilities for scheme
> > and java scripts that freak around with my objects. with language bindings
> > requiring physical embedding that's utterly impossible ;)
> 
> I agree this is a concern that argues for the proxy approach.  However,
> the embedded approach does not preclude language mixing, as long as
> at most one language at a time needs to do embedding.  It may also be
> possible to use a hybrid approach, combining embedding and proxies,
> for the rare cases where that is needed.

hum, how'd you decide then which objects to force-create proxies
for then and which not? and how will language bindings figure
which one is in charge of doing extra object padding and which not?
to me, this sounds like an enourmous complexity imcrement at doubtfull
benefit.

> But even if you think proxies is better than embedding, I think it is
> still worthwhile to offer embedding as an option, as long the cost to
> the gtk core is minor.  since it clearly is more efficient in at least

for one i think with the above i outlined why i don't believe that
the cost to the gtk core would be minor.
for another it's not at all clear to me in what apps you'd be
more efficient with your aproach. if you have some real figures to
back that up, i'd certainly be interested in them (e.g. by adding
counters to other already bound applications, not necessarily java,
and compare the amount of proxies vs. the amount of gtk objects).

> some applications.  Adding a mem_alloc_callback hook seems to me like
> a minor cost, especially since it seems like the kind of hook you want
> to have available anyway.

other than for your embedding idea, why would i want such kind of
allocation hook anyway?

> Of course if you want to use both Scheme and Java the solution
> is obvious: Use Kawa (http://www.gnu.org/software/kawa).  I should
> know that Kawa is an excellent Scheme implementation - after all,
> I wrote it!  (Less biased observers have agreed with me ...)

hm interesting, a scheme binding mapping back to java byte-code.
hadn't heared of that yet. on a more personal note, i'm toying with
support for multiple language backends for one of my applications,
scheme and ruby should definitely be an option, while java would
be nice as well. but i guess there's no ruby->java byte-code
project underway yet, is there? ;)

> -- 
> 	--Per Bothner
> per@bothner.com   http://www.bothner.com/~per/
> 

---
ciaoTJ






[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]