Re: [gtk-devel-list] Re: GtkType stuff




Tim Janik <timj@gtk.org> writes:

> On 5 Sep 1998, Marius Vollmer wrote:
> 
> > Tim Janik <timj@gtk.org> writes:
> > 
> > > > GtkArgs are used to pass values to signal handlers.  Thus, as of now,
> > > > signal handlers can only have signatures that are expressable with the
> > > > current GtkArg structure.  Thus, there is no signal handler that has
> > > > arguments with modes that are anything but "in".  Because the GtkArg
> > > > structure can not express other modes.
> > > 
> > > hm, there at least have been some signal handlers like this, i.e. the
> > > old GtkWindow::move_resize signal (still in the 1.0.x tree):
> > >   gint (* move_resize) (GtkWindow *window,
> > >                         gint      *x,
> > >                         gint      *y,
> > >                         gint       width,
> > >                         gint       height);
> > 
> > Ah, I wasn't aware of this one, but I think there is a
> > misunderstanding here.  I think calling the thing `modes' was a
> > mistake and I will call them `flow hints' in the sequel.  C has modes
> > and the way I want to define flow hints is not the same as modes in
> > ADA, or the `var' keyword in Pascal.  The flow hints do not talk about
> > whether we make a new variable when calling a function, or whether we
> > reuse an existing one, but rather, what a function is allowed to do to
> > the values that get passed to it.
> > 
> > Flow `in' means that it is not allowed to mutate that value.  This is
> > different from not being allowed to change the variable (or argument)
> > that happens to hold this value.  It's more like the `const'
> > qualifier.  Actually, it's probably exactly like the `const'
> > qualifier.  Hmm...
> > 
> > There is no way to mutate an integer, for example.  You can't write
> > something like
> > 
> >     1 = 2;
> > 
> > Of course, you can write
> > 
> >     int x = 1, y = 1;
> >     x = 2;
> > 
> > but that is only changing the object that x denotes.  The variable y
> > is of course unaffected and still has 1 as its value.
> > 
> > So flow `in' is all that makes sense for integers, and for most of the
> > other GTK_TYPE_ types defined so far (GTK_TYPE_OBJECT, GTK_TYPE_BOXED
> > and GTK_TYPE_STRING being the exceptions).
> > 
> > But you *can* mutate an array.
> > 
> >     int array[1] = { 1 };
> >     int *x = array, *y = array;
> >     x[1] = 2;
> > 
> > This is actually modifiying the object, not merely making x denote
> > some other object.  Since y denotes the same object, you can observe
> > the mutation thru y.
> > 
> > The flow hints are intended to make this propagation of mutations work
> > efficiently even across language barriers.
> > 
> > In short, it makes no sense to mark a GTK_TYPE_INT as `flowing out'
> > because there is no way we could mutate the integer.  But we can
> > mutate arrays, and thus, we should be using them for outward flowing
> > information, exactly like C does.

My actual opinion is that if we want to go this route, we should go it
all the way. The argument direction should act as in the CORBA C or
C++ mapping - in that GTK_TYPE_INT | GTK_ARG_OUT gets mapped as int *,
while "normal" GTK_TYPE_INT maps as before. Types that are already
pointers do not get the extra reference.

Anybody looking at this should definitely look the CORBA
mapping. The CORBA mapping is rather complex, so we wouldn't
want to copy it, but some concepts probably carry over.

The way I would do it is that the following get an extra
reference when passed out or inout:

 - Objects that are passed by value in C - ints, floats, etc.
 - Objects that are inherently passed by reference, such as
   GtkObject, or GdkWindow. That is, an out GtkObject is
   passed as an GtkObject **.

While things that are passed by reference in C, but are not
conceptually always pass-by-reference, such as pointers 
to fixed-length structs, do not get the extra reference.

In fact, there is nothing currently defined in gtk.defs that
fits into the latter category, but there is a need for such.
The prime candidate are things like the GtkRequisition argument
to size_request.

Much more tricky is what to do if we provide some way of passing
GLists (or GPtrArrays) as signal or function parameters. This is the
area where the CORBA mapping gets ugly. Probably we should just
forget the possibility of 'out/inout' GLists. 

> > > in general, "in" arguments are always a little questionable for signal
> > 
> > Don't you mean "out"?
> 
> of course.
> 
> > > handlers, because there is 1) no mechanism to check the returned values
> > > for validity upon every handler invokation, and 2) it is not always clearly
> > > defined when such modifications will take effect, i.e. does changing a
> > > value that is passed by reference take effect if modified in an _after
> > > handler?.
> > 
> > Yes, agreed.

 1) ???? For a intepreted languaged, the language binding makes sure
    that they are valid, presumably.

 2) There is no problem for something like TYPE_INT. Each handler
    can modify the return value if it so chooses. An OUT value
    of, say, type GTK_TYPE_OBJECT faces the same problem as a return
    value of GTK_TYPE_OBJECT, except in this case we can actually
    solve the problem! We merely need to make the convention
    that before emitting a such a signal, the caller must store
    NULL in the value. And that any handlers that modify the
    value must gtk_object_unref() the existing value if it
    is not NULL.

> > > since this distinction is not clearly made in C, other than passing
> > > the values by reference, signal handlers implemented in C only deal
> > > with either "in" values or with "inout" values in that sense. so the
> > > required distinction boils down to one bit of information, right?
> > 
> > Hmm, no.  The flow hints would be used to avoid unecessary conversion
> > operations.  A Scheme array can not be used directly as a C array, we
> > have to convert it first by allocating a C array of the right size and
> > then filling it from the Scheme array element by element.  When the
> > called function returns, we have to synchronize the two arrays again.
> > The flow hints would allow us to skip one of these conversions.  When
> > the flow is `in' we don't need to convert after the function has
> > returned; when the flow is `out' we don't need to convert before it is
> > called; and when it is `inout' both conversions are needed.

> well, ok, i got the idea. but what do we actually need the flow hints
> for, then? gtk's type system doesn't know about arrays currently, and i
> think you wouldn't want to do this for objects as well, right?

Think about the rectangle in size_request. 
 
> > That's 1.5 bits, but it's of no fundemental importance whether we need
> > 1 or 2 bits to encode the flow hints, right?
> > 
> > > for one thing we could, while preserving the current _GtkArg struct
> > > size, reduce the actuall type information to 31 bits and have
> > > another one, indicating "inout" behaviour:
> > > 
> > > struct _GtkArg
> > > {
> > >   guint type : 31;
> > >   guint is_inout : 1;
> > >   gchar *name;
> > >     
> > >   union {
> > >   [...]
> > >   } d;
> > > };
> > > 
> > > but this seems somewhat hackish, and i'm not sure that we do need
> > > this at all, since the destinction can already be made through the
> > > fundamental type anyways.
>
> > Yes, agreed.

I don't. The direction of the argument is not fixed for a single
fundemental type, or even a single type. Now if you want to say that
the type argument to gtk_signal_new is the bitwise or of a type and
some flags, that might make sense.

> > > to carry the above mentioned on-bit-mode-information a bit further,
> > > what about providing:
> > 
> > I think the following is cleaner.  It would restrict us to 64
> > fundamental types, but that is still plenty.  We would have: top 24
> > bits: seqno, then 2 bits flow hints, last 6 bits fundamental type.
> 
> trade some seqno bits for that then, so we only have 22 seqno bits available,
> that still makes up more than 4 millions, which is pretty much enough for
> a single program, right? ;)
> 
> > typedef enum {
> >   GTK_FLOW_IN = 0,
> >   GTK_FLOW_OUT = 1,
> >   GTK_FLOW_INOUT = 2
> > };
> 
> i'd rather like these enum values to carry the bits directly, rather
> than their shift count, because they are actually flags indicating certain
> behaviours.

I wouldn't think of that above a shift count. (It isn't) But
rather a 2 bit bitfield shifted by some fixed amount.

> some of the above GTK_FLOW_* flags needs to indicate the C language
> pass-by-reference behaviour, even if you don't intend that as a meaning
> for the "flow-type" concept. otherwise, we'd be pretty much forced to change
> all GtkType handling code in existance.
> 
> > > with this, for the above mentioned ::move_resize signal, you'd actually do:
> > >     gtk_signal_new ("move_resize",
> > >                     GTK_RUN_LAST,
> > >                     object_class->type,
> > >                     GTK_SIGNAL_OFFSET (GtkWindowClass, move_resize),
> > >                     gtk_window_marshal_signal_1,
> > >                     GTK_TYPE_BOOL, 4,
> > >                     GTK_REFERENCE_TYPE (GTK_TYPE_INT),
> > >                     GTK_REFERENCE_TYPE (GTK_TYPE_INT),
> > 
> >                       GTK_TYPE_SET_FLOW (gtk_type_get_fvec (GTK_TYPE_INT,
> >                                                             GTK_FLOW_INOUT)),
> 
> so this would become
>                         GTK_TYPE_SET_FLAGS (GTK_TYPE_INT, GTK_FLOW_INOUT),
>                         GTK_TYPE_SET_FLAGS (GTK_TYPE_INT, GTK_FLOW_INOUT),
>                         [...]

How about simply:

 GTK_TYPE_INT | GTK_DIRECTION_INOUT

? GTK_TYPE_SET_FLAGS, to my mind really indicates that your
are modifying the type - compare GTK_WIDGET_SET_FLAGS

[...]

> > [ Declarations in header files ]
> > 
> > > > I think the same, but I don't want to stop at being close.  I want to
> > > > get there.
> > > 
> > > that's what i intended the comment-enclosed hints for, just like
> > > owen did for enums.
> > 
> > Yes, but ommitting these hints would make the system err on the
> > dangerous side, not on the safe side.  When someone writes a new
> > function and does not provide the necessary hints (because he doesn't
> > know or care anbout them), we get incorrect behaviour.
> > 
> > That is, I don't want to have the possibility for introducing bugs by
> > not knowing about the *.defs system.  I can live with incomplete
> > functionality, tho.
 
> i'd be interested in hearing owen's comments on this issue, since we
> seem to be stuck wrt the amount of headaches we want to cause for
> the intermediate gtk programmer (occasional widget writers).

I don't want to go the route of having GTK+ written in some
hybrid of scheme and C. If a widget writer doesn't get the
comment enclosed hints right, then C will still work right,
it will just happen that language bindings may not. But
then it is an opportunity for somebody to submit patches.

I think that most C programmers will feel more comfortable with:

GdkWindow*    gdk_window_get_pointer	 (GdkWindow	  *window,
					  gint		  *x,   /*< out >*/
					  gint		  *y,   /*< out >*/
					  GdkModifierType *mask /*< out >*/);
 
Then with:

(define-func gdk_window_get_pointer
  GdkWindow window
  ((GdkWindow window)
   (out int x)
   (out int y)
   (out GdkModifierType mask)))

In fact, I'm sure of it.

Regards,
                                        Owen



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