Re: Structs in gobject-introspection + Javascript



Hi,

On Sat, Nov 8, 2008 at 5:07 PM, Owen Taylor <otaylor redhat com> wrote:
> [ Sorry for the long cc: list. Do we need gnome-js-list gnome org? ]

It would be pretty low-traffic, but maybe so. I guess it could include
both seed and gjs. As long as nobody minds, maybe it's simpler to just
use language-bindings, since language-bindings is so low-traffic
anyway. Anyway, no strong views.

> Here's what I came up with. An actual attempt to implement structures
> would likely run into issues I haven't thought of here.

Probably nothing too major, except for writing the actual
struct-offset-computation code.

> 1. Structs are supported if they are:
>
> - Have no pointer fields. (They can have nested structures{1} and union
>  fields). Call these simple structures.
>
> Or:
>
> - Are registered as boxed types with GObject
>
> Note that some structures, such as GdkRectangle or GdkColor are both
> boxed and simple structures. {2}

Is it desirable to support not-registered-as-boxed structs, or could
we just register them all as boxed?

Not sure it is materially harder to support non-boxed types, so maybe
it doesn't matter.

One consideration is that some boxed, maybe GdkCursor (don't remember
the examples) ref rather than copy in their copy function. I don't
know if it ever makes a difference. I believe the rule is that if it's
refcounted and mutable, it should be a GObject to be nicely bindable.
Fixing GObject to avoid its current overhead (as discussed on
whichever bug it is) would help here.

> 2. When a structure is passed from C to Javascript, there is an implicit
> copy made. Thus:
>
>  var some_global;

or "let someGlobal" ;-)

> 4. In any place a a simple structure is expected, any other object that
> has properties for all the objects fields can be used. So, you can do:
>
>  window.invalidate_rect({ x: 5, y: 5, width: 100, height: 100 }, true);

An interesting question this raises is whether you would ever bother
(for simple structs) with the current boxed.c type of implementation
where the JS object contains a C struct. I would say no; when you
copy, just create a plain JS dict with the appropriate properties. So
there would be no JSClass corresponding to simple structs.

For boxed structs, this does create a strange multiple-codepaths
situation, if the boxed struct is simple also (is not opaque). For
opaque boxed structs, the JSClass wrapping a C pointer is clearly
necessary.

Perhaps implementation-wise, the issue is whether the struct is opaque
or not... whether having the values of all struct fields is equivalent
to having the struct. Not whether the struct is boxed. If the struct
is not opaque, then there's never a need for a special JSClass, just
always map as a plain JS object. if the struct is opaque, then we need
a JSClass wrapping a boxed type.

Is it possible to have a boxed type with some non-opaque / visible
fields, that still must be treated as boxed and not just copied by
value? GdkEvent I guess is an example since copy by value breaks? But
for GdkEvent, do we want to allow a plain object with the appropriate
fields to substitute?

I'm wondering if we can avoid multiple codepaths, where to marshal the
args to something that takes struct Foo, we have to handle both a
wrapper-object-for-C-struct and a random JS object. (Though, just
doing one codepath and always using JS_GetProperty would work, it
would be a lot less efficient than getting the wrapped C struct and
then memcpy'ing it in the case where the wrapped struct exists)

Just thinking out loud, don't know

>  copy() - returns a new object that is a copy of this object [2]

clone() would be the usual name for this in JavaScript I think,
various xpcom objects use clone() and prototype.js adds Object.clone

I don't think SpiderMonkey's Object class has clone() already but maybe it does.

>  set() - assigns a value of another object of the same type to the
>         object [3]

Does imports.lang.copyProperties() always do the same thing?

If someone passed in a dict as a struct, it would not have these
methods. That could be a little surprising; perhaps it is cleaner if
non-opaque structs are always just plain objects, and have no special
methods at all. Are copy() and set() really more useful on a rectangle
than they would be on any other JS dictionary?

Under what circumstances would some JS code know it had a special
GdkRectangle proxy with copy() and set(), vs. just a dictionary with
x/y/width/height fields?

> So, equivalent to the size-request example above you can do:
>
> widget.connect('size-request',
>                function(widget, request) {
>                    request.set({ width: 100, height: 50 });
>                });

In the size-request case, what is going on with the copying? Do we
copy the Requisition, pass it to the handler, then set the original
requisition back to the copy's new values?

> [1] Or is it better to do out structure parameters like you would do out
> integer parameters - as a return value or an array of return values?
> I generally like the suggested method better because it corresponds to C
> code and to some of the existing GObject language bindings.

It seems like it's necessary to map out how some contrived method
signatures would work, like:

struct Foo;

Foo* foobar(out Foo, out int, out Foo)

Are we saying that some out params (structs) are done in JS by passing
in dictionaries, and some are return values, so:

let foo1 = {};
let foo2 = {};
[rval, intOut] = foobar(foo1, foo2);

And fields in foo1, foo2 would get set?

It seems a bit simpler to me if we just map all "out" params as return
values (which is how it works now, iirc):

[rval, foo1, intOut, foo2] = foobar();

> {2} There is no way to tell distinguish a a simple structure
> registered as a boxed from a boxed object with internal private state.

This may reinforce the idea that opaque vs. plain old data is the real
distinction, at least for certain purposes, rather than whether it's
registered

None of the above terribly thought out, just figured replying quickly
would be helpful.

Havoc


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