Re: New 'GObject' as base for GtkObject?




Karl Nelson <kenelson@ece.ucdavis.edu> writes:

[...]
>  [ I wrote ]:
> > This does not mean that we would get rid of global emission
> > lists, but if we moved GtkObject it to a libgobject, I'd definitely
> > imagine adding the necessary locks to make it GLib-style thread
> > safe. (That is, the internal data structures would be thread safe) - 
> > and  make the emission lists per-thread.
> 
> (Owen this was a seperate discussion I had at some earlier point
> with Tim, IRC.  I don't think you ever saw this one as it may
> have been private email and later irc.)  
> 
> My argument for why it would be better to make the signal emission 
> capable of being being completely thread afe has always been
> shot down as not necessary because you need to have global locks
> for gtk+ any way.  If this part comes off of gtk+ then it
> will be more of a reason to either remove those parts needing 
> locks or add locks to those parts.  :-)  If we are talking about a
> general object system to be used in things like sound systems
> emits of signals must become something better than a global lock.
> (At least from what I would guess.)

Well, yes. 

There are two separate issues here:

 - The ability to emit signals on two different objects from
   two different threads. 

   This is definitely worthwhile if we split out the GTK+ object
   system and comes almost free if you make the emission lists
   per-thread. (The only remaining difficulty is some free
   lists that would need to be locked or replaced.)

 - Some sort of automatic locking so it is safe to emit signals from
   two different threads on the same object.

   Not easy to do, and not that useful.

> > > For example,  from the C++ prospective (these cover all of gtk+
> > > and some reflect on the object system)
> > > 
> > > - you can't use static cast at all in C++ because the gtk+ object
> > >   model has no concept of casting to primitive object and use
> > >   its functions.
> > 
> > Eh? I don't follow. If you map a GtkObject onto a static C++
> > heirarchy, then static casts work fine. 
> 
> > I mean ... certainly if you create a Gtk_Button structure in gtk--
> > you can do:
> >  
> >    button.add(label)
> > 
> > which is doing implicit static casts...
> 
> Static casting to a lower object in C++ means something special.
> If I want to call previous implementations of a virtual function
> I do...  
> 
> inside box methods
>    Gtk_Container::add(w);
> 
> or 
> 
> outside box methods
>    static_cast<Gtk_Container&>(box).add(w); /* skips Box::add */
> 
> We have come to accept this feature as missing as it implies
> a lot about the virtual function nature.  However, it is a
> very good example of where wrapping can never be equal.

Well, I'd say that it was a design decision in GTK+ that:

 - You cannot do this external to a GTK+ object
 - Within the GTK+ object, the only thing you are allowed 
   to do is to chain to your parent class's implementation.

If you don't make these restrictions, then you risk corrupting
state, because the caller is bypassing functions that the
class assumes to be called. For instance, if a class that derives
from GtkEntry called GtkWidget::map directly instead of 
chaining to GtkEntry::map, then the new windows that GtkEntry
adds simply won't be mapped.

So, for GTK+ widgets, the restrictions you complain about
are harmless, because from a coding-guidelines standpoint,
you would not be allowed to do those things even if they
were supported in the object system.

> > > - The type argument interface is almost worthless as it does
> > >   not have any way of typesafety, nor can it be easily cast as
> > >   a stream.  (args interface should take float, int, or strings
> > >   and handle them all instead of casting to what is exected and
> > >   barfing!)   In otherwords be typesafe and if you can't be
> > >   able to take all inputs and deal with them safely. 
> > 
> > Hrmm? I guess you are referring to the varargs interfaces in 
> > GTK+ ... but those are going to be wrapped anyways by a
> > language binding.
> [...]
> 
> Yes, however, Guillaume has pointed out several places in the 
> Gnome interface where this was the only way to access something.
> Those places give us nightmares and thus we end up rewritting the
> whole access functions.  

Hmmm, the only thing you seem to lose here is 

 a) automatic generation of binding glue
 b) some amount of efficiency

And for a) it should be quite possible to automatically create
argument-setters and getters from the results of querying the
type system.

(It is a bit troublesome right now that some forms of type information,
like methods signatures, are only available by header-file parsing,
and other forms of type information, like signal and argument
specifications, are only available as a runtime query. But
it is still possible to discover everything if you are willing
to compile and run a small query program as part of the 
generation process. gtk-doc does this.
 
[...]

> > > - Too many damn fragments which all have their own reference
> > >   interface.  Why can't they all come from a very simple light
> > >   interface.
> > 
> > Well, perhaps we can address this somewhat if we create a lightweight
> > GObject, but there is definitely a need for even lighter "objects" - 
> > things that don't present inheritance or virtualization at all.
> > (e.g. GString). This was basically the idea of the BOXED type
> > that Marius introduced though never fully implemented. That is,
> > you have a "object" represented with a pointer, and there are
> > two functions that act on 

Hmmm, I think I forgot to finish this thought ... what I was going
to say was:
 
 two functions that act on the pointer - a function to duplicate
 the pointer and a function to free a copy of the pointer.
 
> Yes, this is definitely where this discussion is heading.  (I
> think that is a very good thing.
> 
> > > - lack of multiple inheritence.  Really it is much more OO to
> > >   define an interface (which may have some data like a signal)
> > >   and then have every thing that has that interface inherite from
> > >   it.
> > 
> > Multiple inheritance is just a complete struggle to implement as
> > compared to single inheritance, and doesn't map well onto C.
> > Also, there is considerable school of thought out there 
> > (which I belong to) which says that multiple-inheritance of
> > implementation is generally a worse way of doing things than
> > aggregation.
> 
> I think I have another way to implement it which might be more up
> your alley.  Unfortunately, it may take some time to bubble up
> into an acceptable implementation.
> 
> I believer firmly that MI is the best way to do some things in the
> interface.  For example, a frame may have a "text", a label has a "text",
> a menu item has a "text".  Therefore the right way to do things
> would be to define a text interface, then define an implementation
> to draw one, then use those implementations in each of the widgets
> so they all share the code, and present the user with the text
> interface.  Then anything that you can do with a label works
> with frames label and so on.  

Well, I don't want to quibble with examples, but in this case,
it may illustrate the general point. For 1.4 we will be making
the text in a frame a GtkLabel ... so we only have one form
of text thing ... a GtkLabel, which is then used in GtkButton
(as currently) and in GtkFrame.

For this aggregation certainly works quite well. And with 
multiple-inheritance of implementation, you will be in serious
trouble if you have a widget that has _two_ text fields.

> This approach also allows for a work allike, were you take a text 
> interface and write your own implementation.  This is more
> like multiple interface.
> 
> Of course there is another way to achieve the same effect.  That
> is just to have only multiple interface that is exportable.  Then
> the label in the frame is a real label that you export its
> interface to the user.  (But then what happens when you want
> a box instead of a label.)  

For 1.4 if you want to put a pixmap or a checkbutton, or a CList
in the slot where the label currently goes, you'll be able to do 
that.
 
> I think the right solution is to allow for multiple inhertance and
> try to make lightweight objects that can be used in composition.
 
If you s/multiple inheritance/multiple interfaces/ than that
is my basic opinion.
 
> Having said what I think is right I want to state what I 
> feel is completely wrong.  That is the Gtk+ habit of taking
> a widget and using parts of the methods while deriving from
> it.  
> 
> IE.
> 
> GnomeApp comes from GtkWindow, but it has replaced the contents so
> all the GtkWindow methods can't be used.  While GtkWindow is a
> GtkContainer which can't have multiple contents, so the add method
> means totally different things.  And the GtkContainer comes from
> GtkWidget, but that has special functions for extracting info which
> exists in only 3 widgets....

What 3 widgets are these? GtkWidget has a few hacks around
the lack of multiple-interfaces, but they don't seem relevant here

> Thus GnomeApp has dozens of methods that don't belong and are not
> useful to down right harmful!  Clearly, GnomeApp which decends from
> IsA window should have been a HasA window and works like (IsA) a
> widget.

I don't see where GnomeApp has "dozens of methods that don't
belong".

Although there are problems with the functions from GtkContainer -
every method from GtkWidget and GtkWindow works fine. 
GtkContainer has only ~10 public methods, and some of these
(gtk_container_set_border_width()) work fine. 

There are still issues with composite widgets and
gtk_container_add() / gtk_container_remove(), but I don't think
those are inherent to the basic setup.

The basic setup is that a composite widget must derive from the
outermost container, so that we can add it to another widget with a
single gtk_container_add().

Now, this doesn't strictly apply to widgets that are toplevels
such as GnomeApp ... GtkMenu is an example of such a widget 
that does _not_ inherit from GtkWindow, but hasA GtkWindow
instead. 

However, since we need to figure out how gtk_container_add() should
work for composite widgets that are not toplevels, there is no
advantage in doing something different for the toplevel composite
widgets.

[ Any replies to this should go to a different thread.. this
  thread is far to big already ]

> (C coders don't have much probelm with this other then
> it is a pain to newbees.  In C++ this is a complete melt
> down of the OO system!)

I think you have to accept that just occasionally there will
be inherited methods that don't apply to all child types,
and that you may need runtime warnings. I would consider
these small quirks rather than complete meltdowns of
the OO system. 
 
[...]

> OFF TOPIC (for GObject but still relevent to gtk+)
> 
> Sorry, I was just spouting off at this point... but you and
> I have had discussions before on this with the iterator 
> concepts for accessing gtk+ list members (not glist).  In C++
> I have the pointer to the location of a GtkListItem, but I have
> to find its number in the list (O(n)) and then pass that to
> gtk+ which will go through the list again to find the element O(n),
> just to get the current value of a field which I then want to set
> which has to do the same thing over again.  This is fine if
> the list size is 8, but if it is 1000 be have a big overhead.  
> Now just imagine I was changing some field in every item of the
> list that is n/2*4*n => O(n^2)
> 
> Gtk+ seems to want to install caches and other such kludges to
> turn the number to item pointer.  But this just plan doesn't work
> for us.  It would have been just as simple to define the 
> procedures to use the pointer to the item and then have wrappers
> that use the index number.  It would give the same interface to
> the user, but much better to wrapper writer.  You can still 
> place the caches but I am sure that users can responsibly use
> a GList* to navigate arround. 

I guess you are talking about GtkCList. The fact that GtkCList uses a
GList internally is probably a mistake to begin with.  It probably
would be better off with an array, or yes, it should provide 
interfaces that are more iterator friendly.

(I don't think that anybody would defend the fact that the common:

 row = gtk_clist_append_row(clist, ...)
 gtk_clist_set_row_data (clist, row, ...)
)

is O(n). Actually, note that GtkCTree goes to great lengths to
duplicate all the functions and provide interface which takes node
pointers instead of row indices ... so clearly we just have a
interface mess rather than an intentional design to screw gtk-- over.

[ Again, responses to this should be split into a separate thread ]

Regards,
                                        Owen



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