[prev in list] [next in list] [prev in thread] [next in thread] 

List:       kde-freeqt
Subject:    Re: [freeqt] Relay++ library [long]
From:       Christian Boos <boos () arthur ! u-strasbg ! fr>
Date:       1998-09-28 23:14:28
[Download RAW message or body]


[Warning: this is a lengthy mail: the most important part of this
message is an advocacy which can be found below the [********] lines,
and the conclusion, but don't jump on the conclusion without reading
the advocacy :) ]

Olivier Galibert writes:
 > [...]  What   about an  hypothetical QNumberEntry  class  sending
 > valueChanged(int) or valueChanged(double) depending  on the user entry
 > (to avoid precision losses), and QLCDNumber?  You could easily have:
 > connect(entry, SIGNAL(valueChanged(int)), lcd, SLOT(display(int)));
 > connect(entry, SIGNAL(valueChanged(double)), lcd, SLOT(display(double)));
 > 
 > and the lcd number will happily display the value dynamically.

Ok, for that I can't avoid the explicit typing.
Maybe some more macros will be helpful for that:

#define SIGNAL1(c,m,a) ((void (c::*)(a))(&c::m))
#define SLOT1(c,m,a)   ((void (c::*)(a))(&c::m))
(and so on)

And your example can be written in Relay++ :

 connect(entry, SIGNAL1(QWhatever,valueChanged,int), 
	 lcd, SLOT1(QLCDNumber,display,int));

 connect(entry, SIGNAL1(QWhatever,valueChanged,double),
	 lcd, SLOT1(QLCDNumber,display,double));

Again this is not Qt compatible.


 > It  is.  Not only  we're actually  source-compatible,  but we're  also
 > invocation-compatible.  You only have to  replace "moc" by "magna" (or
 > make a link),  and it works.   Actually the name  is different to make
 > having both Qt and Harmony on a system easier.

This is secondary issue.
 
 > > So we can keep magna, and make it produce the appropriate syntax for
 > > Relay++. The only complexity I see in that process is for handling 
 > > the very special situation you showed above (sig(int) and
 > > sig(double)).
 > 

 [***********************************************************************]

 > That is   another  problem.  You'll  have to  convince   us  that your
 > solution is better.   For  now I  think  that magna's  code  uses less
 > ressources, is faster, spends less time in locks and is less complex.

 [***********************************************************************]

Ok, that's the real issue. I'll advocate some more:

On the "negative side":

* Relay++ uses some resources, that's right. I wanted to integrate 
  the s/s mechanism with multi-threading, the most important part of 
  this being the slot server. For that, I took what appeared to most 
  appropriate tools, namely mutexes. So you end up with one mutex in
  each Realy, and in each Connection too.
  In french I would say "je me suis donné les moyens de mes ambitions" 
  ...

* Yes, I spend some time in the locks, and yes I'm aware it was 
  a little bit complex to design cleanly (I hope it is fairly done
  now, but of course they are certainly some bugs left).


On the positive side:

* The (extensible) connection scheme provides far more flexibility
than Qt (I'll say Qt for both Qt and magna).

 With Qt:
 - With Qt, member functions signature must match EXACTLY (and I don't
  even speak of typos in signal  and slot names  which are detected at
  run-time)

 With Relay++
 + With  Relay++, an   argument of a     slot is compatible with   the
   corresponding argument of the signal if it can be converted from
   it.
   If this automatic type-conversion is not wanted or ambiguous, you 
   can be more explicit about the type (see the above macros)

 + you can additionally get a reference on the sender 
   in your slot, with the EXACT type (ie the most derived one) if you
   want (this is automatically provided by the 'generic' family of
   connections).
   This is very powerful, in term of the Observer pattern, it means 
   that not only you can use the 'push' model from communicating
   arguments from the subject to the observer (as with Qt s/s), but 
   with generic connections you can use the 'pull' model as well.
   This would permit to get rid of the dangerous QObject::sender() 
   member function (this provided the same functionality, but returned
   a pointer on a QObject*).
 
 + you can provide default values at connection time. 
   Tero said that this was an appreciated feature, in Gtk--.

 + you can as well ignore some arguments.

 + you can even use regular functions as slots.

 + signal relaying is transparent : since a signal is nothing more
   than a function member (which calls trigger() of course), you
   can connect a signal to another signal and get the expected 
   behavior.

 + if all this isn't enough for your need, you can even write your 
   own extensions   (that should not be too hard :)

 + you can easily arrange that your slot get executed in a specific
   thread, see below 'The Slot Server'.
  

* Reentrancy and Multi-threading issues
 
 With Qt:
 - no reentrancy at all (I guess, since I haven't seen the code)

 With Magna:
 - very limited reentrancy support (none of the (+) listed below, am I 
   right ?)

 With Relay++:
 + extensive MT-support and reentrancy support (at least in spirit, 
   not all situations were tested, the code is too young)
   -> you can emit other signals in slots (this is not even safe in
   magna, since it iterates on a list which is subject to be modified
   in the meantime)
   -> you can do connections and disconnections while running a slot
   (the QObject::connect function is not MT-safe at all: you lock the
   'from' side, but manipulates the 'to' side without locking the 'to'
   side; of course this would lead to deadlock situations, and there's 
   no simple answer to this problem... hence my non-simple answer with
   individualizing the connection in an independent object, which
   permits two-level locking and is thread-safe without being prone to 
   deadlocks. Like I said before, full MT support has a cost).

 + Thread specific data		(joke, it's easy to add :)

 + a  SharedResource class, which may replace  the existing 'qrefcnt' 
   stuff. Why? It provides logical deletion, which leaves objects
   in a 'delete pending' state. You may still use such deleted
   objects, but you no longer should take additional references on it.

  ++   
 ++++ ... and now the most important feature in my opinion: 
  ++

   The Slot Server

   What's that? In short, it is provided for making multi-threaded GUI 
   apps as easy to program as a regular (non-GNU :) 'hello'.

   // Example section, taken from kdehelp. Simply do:

    SlotServer *async_update = new SlotServer;

    connect( view, SIGNAL(QScrollBar, scrollVert) ),
             SLOT(KHelpWindow, slotScrollVert) ),
	     *async_update );

  // the slot is now asynchronously executed in a dedicated thread

  And with that, \begin{shout} you're f... HTML widget won't scroll
  forever just because you stayed too long on the scrollbar's down button!
  \end{shout}.

  ... just because signals are not buffered, but are replacing each other 
  when they are posted. So no more than one call (for a particular 
  connection) can be scheduled when another is being executed.
  
  I hope this is an argument, or else I'm hopeless :)


[***********************************************************************]


In the hypothesis that harmony adopt my Relay++ library, I would
suggest that the internals of Harmony use it at its full power 
(ie write all the 'trigger()' calls by hand, for example).

Specifically written code for Harmony could also exploit the
flexibility of my connect function to use whatever kind of connection
they want.

The only difficult point is how to deal with existing applications, 
namely KDE.

I can imagine some solutions:

1) rewrite them. 

That's the easy way. Really. They will gain Relay++ typechecking
facility, at the cost of a minor rewrite of all the occurences of 
the SIGNAL and SLOT in the applcation. This should take less than an
hour even for big apps. 

Can we automate this. The more I think about, the more I think Olivier 
is right. Since you explicitely need a class name compatible with the 
member function used, you face a very difficult parsing problem for 
retrieving this info in plain source code. Even if the code is not as 
obfuscated as Olivier's example (at the botton of this mail), it may
be hard for an automated tool. OTOH, a programmer can figure this at a 
glance.

2) don't use them

KDE will certainly 'split' as soon as TT release Qt 2.0 
Some developer will stick with the 1.40 features, other would want to
benefit from 2.0 features... and other would want to benefit from
Harmony features. I'm perhaps pessimistic, but I don't think that
Harmony will be usable before 2.0 ships.  At this time, if you don't
want to see everybody rush on Qt and forget Harmony, we should have 
something very attractive for them. The freetype, themes, are such
things, but so is (IMHO again) the Relay++ framework for s/s (I won't
advocate again, feel reassured :)

What should we do then, if TT adds some specific licensing stuff for
preventing specifically any API cloning? Should we stick forever with 
Qt 1.40 features? I don't think so. Qt was at the top several years
back, but now it has to evolve. Since we can do this, we shall do it.

OK, I was perhaps a bit too provocative here, don't hesitate to
correct me, especially the KDE people. Perhaps there's already something
decided regarding those issues.



Now some comments about the RTTI:
 
 > >  > You also need the preprocessor for the  RTTI part of Qt (className and
 > >  > inherits).
 > > 
 > > I already tested some things about that. Here's an excerpt:
 > > 
 > > 
 > >   public: // -- RTTI	[note: not source compatible with Qx]
 > > 	
 > > 	const char* className () const
 > > 		{ 
 > > 		  return typeid (*this).name (); 
 > > 		}
 > 
 > This one is wrong.  The name is explicitely unspecified (not the class
 > own name, maybe not the same from one excution to the other).
 > 

Not wrong, only implementation dependent ( to  the compiler's implementation).
egcs do this fine.

 > > 	bool inherits (QObject* other) const 
 > > 		{ 
 > > 		  return typeid (*other).before (typeid (*this)); 
 > > 		}
 > 
 > This one is wrong.  The collating sequence is explicitely unspecified.

Not in my doc (C++ draft version 2). I haven't tested, though.

 > 
 > >   
 > > 	bool isWidgetType (QWidget* widget) const
 > > 		{
 > > 		  return typeid (*widget) == typeid (*this);
 > > 	  }
 > > 
 > > 
 > > ... not source compatible because in Qt, the class info is only a
 > > string.
 > > Perhaps again a preprocessor would do the deal.

In fact, you can again put my two proposal here: rewrite the
apps.

The RTTI's use is very marginal in KDE, and that's a good thing. 
I could only find a few apps that are writing their classname in their
config file. I'm not enough knowledgeable of KDE to see if this is
important or not. Surely not, otherwise all apps would to this.



[about the transparent use of threads]
 > 
 > They are if you don't  use them [...]

indeed...

 > [...]
 > transparent.  Threads   are  transparent   if   you  don't   use  them
 > explicitely (sorry this part of the code has been in my brain for some
 > time but is not written yet).

So tell me (us) about, at least. How does it compare with the slot
server?

 
  > > So my proposal is to keep the preprocessor to translate legacy Qt apps 
 > > to Harmony apps, and use internally what we think is best. Of course
 > > I would respect your decision not to integrate Relay++ in Harmony, 
 > > that's why I made a separate lib.
 > 
 > For  now   the  preprocessor   doesn't have   to   translate anything.
 > Translation  is  a difficult problem,  and personnaly,  were I  mad or
 > bored enough to attempt  it, I'd target Gtk--  rather than yet another
 > library.

Oops, I forgot to compare with Gtk-- in my advocacy part. Hum.
Gtk-- is statically type-checked, yes. But its not MT-safe, nor is 
it close to Qt's syntax. Remember, I tried to keep a syntax as close
to Qt as possible  when writing C++.
And Tero added support for return type for signals. I would eventually 
do that if something convince me it's useful.
I don't know either if you can integrate you own  connection extensions 
without modifying the core of Gtk--.

Ah I forgot! If my poor 60 bytes for a Relay object where too much for 
you, don't even look too close at Gtk-- ... a Widget object contains more
than 40 Signal_proxy* objects, each costing, hum, 16 bytes. 
Correct me Tero if I'm wrong. 


 > As  it comes to changing   magna's  generated code, I'm not  religious
 > about it put I put a great deal of effort in it to make  it the best I
 > could.  The  only  missing thing right now  is  disconnect.  So you'll
 > have to show me in which way your code is better  than the current one
 > to convince me.   BTW,  it's the full  compatibility with  Qt's syntax
 > which was the  main cause of Jo's code  removal at the time (MT safety
 > was secondary). See the gtk--* code in the repository.

Easy, I provide disconnect :) :)
No, sincerely we could keep magna for generating Qt compatible RTTI,
if you want, since RTTI in itself is a bad thing, no matter how it's done.
But for signal and slots, I honestly think my library is a better
alternative. Let's wait for having more opinions on that point.

 
 > Allow me  to doubt the "easily identifiable"  part.  I'm in particular
 > afraid of the oh-too-clever
 >   struct {
 >     QObject *obj;
 >     char *slot;
 >   } *slot_list[] = {
 >     { obj1, SLOT(slot1) },
 >     { obj2, SLOT(slot2) },
 >     ...
 >   };
 > 

You convinced me with that, though I wasn't able to see anything else
than 'standard' usage (ie in some form of connect) in the whole KDE.
The problem, as I said before,  is that  even in the standard usage,
you can't easily retrieve automatically the CLASS information which
would be needed for using Relay++



CONCLUSION

Ok, with Relay++, Harmony will not be 100% source compatible with
legacy Qt apps, only, say, 99% (*)
The question is whether you think the features of my library are worth 
that. 

Perhaps your fear is that the KDE people will avoid using Harmony if it
is not source compatible with Qt? This is wrong. They will use what
they feel is the most appropriate tool for the job. I even read
somewhere that there was a Tk extension which adds KDE compatibility!
If you can now write KDE apps with Tcl, you certainly will be able to
do so with an enhanced replacement of Qt.

In short, Harmony should not be a Qt clone, but a better Qt.


-- Christian	


(*) estimated by comparing a 'grep "connect" *.cc'  with a
 'wc -l *.cc' for a few KDE apps

[prev in list] [next in list] [prev in thread] [next in thread] 

Configure | About | News | Add a list | Sponsored by KoreLogic