Structs in gobject-introspection + Javascript



[ Sorry for the long cc: list. Do we need gnome-js-list gnome org? ]

So, I've gotten a little annoyed recently at the lack of struct support
in gjs. So, I was trying to think through how exactly the mapping
between gobject-introspection structures and Javascript should work.

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

- Owen

====

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}

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

 var some_global;

 widget.connect('size-allocate', 
                function(widget, allocation) {
                    some_global = allocation;
                });

Is safe.

3. In a callback that has an out parameter, there is a copy made on when
the function exits (no copy is made if the function throws an
exception.) Thus:

widget.connect('size-request', 
                function(widget, request) {
                    request.width = 100;
                    request.height = 50;
                });

Is safe. For an in/out parameter, copies are made both ways. [1]

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);

5a. Simple structures support a "copy constructor" that takes another
object with the right fields.

5b. Boxed structs that are not simple structs have a copy constructor
corresponding to the boxed copy function.

5c. There may a constructor declared in the introspection information.
This is "overloaded" based on argument type with the copy constructor.
The copy constructor takes precedence in ambiguous situations.

6. Every structure object has methods:

 copy() - returns a new object that is a copy of this object [2]
 set() - assigns a value of another object of the same type to the
         object [3]

So, equivalent to the size-request example above you can do:

widget.connect('size-request', 
                function(widget, request) {
                    request.set({ width: 100, height: 50 });
                });

7. Any field declared in the introspection information can be read
as an object property. 

8. Any field in a simple structure can be set by assignment to an
object property. Fields in non-simple structures cannot be set. {3}

9. Assignment to a nested structure has the effect of copying the
structure passed in. So given:

 struct B { 
    int x;
 };

 struct A {
    B b;
 };

===
a = new A({ b: { x: 1 } });
b = new B({ x: 2 });
a.b = b
a.b.x = 3
log(b.x)
===

Gives 2, not 3.

Mapping concerns
================
[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.

[2] Is the copy() method necessary? It duplicates the copy constructor
described above.

[3] The set() method is needed for for certain out and in/out
parameters, like the 'pos' argument to GtkTextView::insert-text. It
isn't necessary if we did out parameters as in [1].

gobject-introspection concerns:
===============================
{1} There is no representation in the .gir format that distinguishes
a nested structure from a pointer to a nested structure, other than
c:type. The typelib format is OK.

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

{3} There may be examples where setting non-pointer fields on non-simple
structures would be useful, I think that would need to be marked in
the introspection information if it comes up in practice.




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