PDA

View Full Version : Sanitizing Qt signals



nroberts
5th January 2011, 00:37
A while back I asked here about auto-generating Q_OBJECT classes so that I could translate Qt signals into boost signals. It more or less resulted in a flame war filled with nonsense and bad advice but one link posted in the lot ended up providing me with the linchpin that would allow me to solve the problem. I'm not done yet, but I do believe the problem solved...needing only to be implemented. I've started a blog article series that will start from the beginning and show how to implement it.

One cool thing about this article is that it will go over the use of a lot of more modern C++ techniques involving template metaprogramming. The goal is to wrap Qt signals into an easy and quick to use function that brings type safety and static typing back into the show in addition to the ability to connect ANY function lookalike to any Qt signal.

Here is the first entry: http://crazyeddiecpp.blogspot.com/2011/01/quest-for-sane-signals-in-qt-step-1.html

pkohut
5th January 2011, 02:20
Here is the first entry: http://crazyeddiecpp.blogspot.com/2011/01/quest-for-sane-signals-in-qt-step-1.html

Overall I like the concept and will be interested in the future articles. Item 1 seems to be a personal choice, and like you I prefer strongly typed languages. That said, I'd like to see Qt's signals/slots implementation go the other direction (not strongly typed) and have capabilities like Objective-C Categories.

nroberts
5th January 2011, 17:24
Overall I like the concept and will be interested in the future articles. Item 1 seems to be a personal choice, and like you I prefer strongly typed languages. That said, I'd like to see Qt's signals/slots implementation go the other direction (not strongly typed) and have capabilities like Objective-C Categories.

IMHO, if you want the features of Objective-C then you should use it. At the time I was using it you couldn't use C++ libraries without wrapping them but maybe Apple's shared that bit with gcc by now? The NextStep API was pretty darn sweet though. The only thing I didn't like about it was the GNUStep implementation using its own sort of filesystem standard instead of being like other *nix apps.

One of the main "ideals" in C++ is that you don't pay for anything you don't use. The abilities of Qt to connect to objects and send them messages they may or may not respond to isn't something I'm going to use, but I have to pay for it. I think it would have been better to provide an add-on reflection support library. In fact, I have built one that I've been using for a long time that does both runtime and compile time reflection. As a separate component it could be used/not-used as needed. Qt'll never do that though, it is what it is and you either take it or leave it.

Yes, #1 is a personal choice. The way I see it though, if you don't like strong typing there are many other choices besides C++ to work with. One common approach these days is to write your low layers that need to be fast and safe in C++, and write your upper layers in Python. I don't see the point of forcing soft typing on a strongly typed language. Of course, when Qt was first written there were not as many options for people as there are now.

At this point, the costs don't bother me because I'm not doing any UI stuff that's got to be fast (minus the drawing, but that's outside the sig/slot mech). I am regularly bothered by the lack of compile time checking though and the inability to connect generic functors to signals. Those two things can be fixed with a wrapper.

Anyway, step 2 is up: http://crazyeddiecpp.blogspot.com/2011/01/quest-for-sane-signals-in-qt-step-2.html

This one does the metaprogramming to rebuild the parameters and call the forwarding function.

tbscope
5th January 2011, 17:58
My first answer to your original post is exactly what you're doing now and you call it poor advice.

I don't get you.

squidge
5th January 2011, 19:43
You make some excellent reasonings in your article in which I am very interested. It would be awesome to be able to connect signals to standard function pointers rather than defined slots so I can put them wherever, without having to worry about defining them in header files with Q_SLOT or suchlike and ensuring I run 'moc' on the file. I always thought it was strange having both the signal and slot name and parameters in ascii text strings (which is basically what SLOT and SIGNAL macros do, for anyone getting confused) and doing so does give away information on how your application is structured and works (which sometimes you may not wish to give someone).

I don't see how you can compare the signal signature to the slot signature (type checking) in the compile stage yet however.

Therefore, I wish you good luck in your quest :)

[BTW, I wouldn't consider this topic 'Newbie' material]

nroberts
5th January 2011, 20:52
[moderated for offensive content] I very much doubt I'll be able to continue providing notice when I've completed this topic. Those interested will just have to go see for themselves, or add yourself as a watcher. Hopefully the thread is allowed to remain so future people looking for this kind of thing can find it, but I have my doubts it'll remain intact.


by wysota: I reedited the post to leave the part containing some merithorical content. This is a special exception as the post is in general in violation of the site rules.

wysota
5th January 2011, 21:27
You make some excellent reasonings in your article in which I am very interested. It would be awesome to be able to connect signals to standard function pointers rather than defined slots so I can put them wherever, without having to worry about defining them in header files with Q_SLOT or suchlike and ensuring I run 'moc' on the file. I always thought it was strange having both the signal and slot name and parameters in ascii text strings (which is basically what SLOT and SIGNAL macros do, for anyone getting confused) and doing so does give away information on how your application is structured and works (which sometimes you may not wish to give someone).

Saying this you end up closer to the concept of callbacks which is exactly what Qt signal/slot mechanism wants to avoid. I too like the idea of using lambdas as slots although this is hardly object oriented and lambdas are not part of the C++ standard yet anyway.


I don't see how you can compare the signal signature to the slot signature (type checking) in the compile stage yet however.
In a general case you can't simply because some signals and some slots do not exist at a time of compilation, for example when connecting DBUS or COM (ActiveX) components.

Commenting on nroberts' idea that signals and slots should be an addon to Qt (if I understood correctly) this wouldn't make much sense as signals and slots are the core of Qt and are used practically everywhere by Qt itself. There has been a discussion whether statically connected signals/slots would be better (sorry, no single link to give for reading) and the conclusion is that it is true that static connections (and invokations) are faster (about twice as fast as Qt's signals) but provided that you want to do anything practical in the slot, the "overhead" will be neglectible compared to the contents of the slot. Statically compiled signals also reduce functionality of signals and slots - you can then forget about dynamic introspection (for example across library boundaries).

And concluding - if you want static signal/slot mechanism, there is one provided by boost. Qt doesn't prevent you from using boost signals in any way. On the other hand dynamic signals (such as the ones in Qt) are much much more flexible, imagine building (on the fly) a meta-object for a remote webservice based on introspected description it provides (like wsdl or something similar) and connecting that directly to signals and slots in your application. It's something that static signals will never be able to do.

nroberts
5th January 2011, 21:47
Saying this you end up closer to the concept of callbacks which is exactly what Qt signal/slot mechanism wants to avoid.

That may be Qt's motivation but the comparison simply isn't valid. If we wanted to compare static signal/slot systems to callbacks we could as validly compare Qt's.



I too like the idea of using lambdas as slots although this is hardly object oriented and lambdas are not part of the C++ standard yet anyway.


OO isn't the only paradigm in C++. Qt also can't connect to members of non Qt classes.



In a general case you can't simply because some signals and some slots do not exist at a time of compilation, for example when connecting DBUS or COM (ActiveX) components.


Those are not general cases, they're specific ones. In general it's actually quite simple.



Commenting on nroberts' idea that signals and slots should be an addon to Qt (if I understood correctly) this wouldn't make much sense as signals and slots are the core of Qt and are used practically everywhere by Qt itself. There has been a discussion whether statically connected signals/slots would be better (sorry, no single link to give for reading) and the conclusion is that it is true that static connections (and invokations) are faster (about twice as fast as Qt's signals) but provided that you want to do anything practical in the slot, the "overhead" will be neglectible compared to the contents of the slot. Statically compiled signals also reduce functionality of signals and slots - you can then forget about dynamic introspection (for example across library boundaries).

Yep, the only comparison they make is performance and then show that it isn't a particularly interesting criteria. They're right, it isn't. If I was worried about performance I'd be rewriting it instead of wrapping it.



And concluding - if you want static signal/slot mechanism, there is one provided by boost. Qt doesn't prevent you from using boost signals in any way.


Which is kind of interesting that you say that because solving the fact that Qt CAN'T connect to a boost::signal directly is exactly the issue I'm solving.



On the other hand dynamic signals (such as the ones in Qt) are much much more flexible, imagine building (on the fly) a meta-object for a remote webservice based on introspected description it provides (like wsdl or something similar) and connecting that directly to signals and slots in your application. It's something that static signals will never be able to do.

And I'm sure it's nice for anyone who actually needs it. For those who don't, which I bet is a vast majority, it's just extra problems.

Of course, this post will probably be deleted and called "offensive".

wysota
5th January 2011, 22:19
That may be Qt's motivation but the comparison simply isn't valid. If we wanted to compare static signal/slot systems to callbacks we could as validly compare Qt's.
Hmm... maybe I wasn't clear enough. What I meant was being able to connect a signal to any function reduces the control over the whole mechanism which is one of the down sides of callbacks. This goes further if we have a connection to an object that gets deleted. What Qt says is "ok, we limit the possibility of using our mechanism to this and this case but we guarantee you won't hurt yourself".


OO isn't the only paradigm in C++.
True. Connecting signals to lambdas doesn't support any other C++ paradigm though.

Qt also can't connect to members of non Qt classes.
True again. And static signals can't convert from strings to integers on the fly (Qt signals can't as well although it's no problem teaching them to do that because of their dynamic nature) as they can't brew coffee and do many other things. The sole fact doesn't make them "bad" or even "incomplete". It's just a design decision which has its advantages and disadvantages.


Those are not general cases, they're specific ones. In general it's actually quite simple.
According to laws of logic, iIf there is at least one case that is not supported by a general hypothesis, the whole hypothesis is not true (it may be true in some specific situation but not in a general one). In other words how do you intend to teach the compiler to distinguish between the two cases just by looking at the source code?


Yep, the only comparison they make is performance and then show that it isn't a particularly interesting criteria. They're right, it isn't. If I was worried about performance I'd be rewriting it instead of wrapping it.
From what I understand you wish to extend the concept while at the same time limiting it in some other place. That's ok but it's hard to call it really an "extension" and it is in no way "superior" to the original.


Which is kind of interesting that you say that because solving the fact that Qt CAN'T connect to a boost::signal directly is exactly the issue I'm solving.
I didn't say you could connect Qt signal to a boost signal (the same way as you can't connect a boost signal to a Qt signal). I said nothing prevents you from using boost signals (for your own things) in Qt applications. I can imagine triggering a Qt signal or a Qt slot from a boost signal should be doable when providing a simple wrapper over the connection. You still need an object somewhere though (not necessarily a QObject).


And I'm sure it's nice for anyone who actually needs it. For those who don't, which I bet is a vast majority, it's just extra problems.
I'm sorry to inform you that if you use Qt for something more than just QStrings there is a very good chance you are using some of the functionality you would like to discard (or "work around"). And even if not you personally than at least the vast majority of beginners with Qt. Please don't assume everybody uses Qt the same way you do. It seems you have a vast knowledge about C++ but it also seems your knowledge of Qt is not that deep so don't state things you can't be sure of.


Of course, this post will probably be deleted and called "offensive".
No but this single sentence might be. You're pushing the limits and doing it on purpose. Please don't test our patience.

squidge
5th January 2011, 22:37
Ok, I've finished reading the articles.

Thinking about it, maybe the best solution is a mix of boost signals and Qt signals, but I'm not sure whether or not this will simply make code more confusing and less maintainable. I'm thinking when you come back to code that hasn't been touched for 6 - 12 months. I don't want to get confused despite the advantages that both systems have.

Also, although your articles contain useful content, I think your bashing of this site and it's members is unnecessary, unprofessional, and not needed in an article when the main focus is about trying to get Qt Signals and Boost Signals to play nice together. People want to read content, not your personal opinion on whether you think a site is any good or not. You also seem to put some comments (such as the #ifdef blocks) out of context. They made perfect sense in the original topic and I believe they were a suitable answer to the asked question at that time.

The amusing thing is that you say we give out "lots of really poor advice", but still post a question just this Monday, 3rd January, asking for help! If the above really was true, why would you post it here?

pkohut
6th January 2011, 05:21
Found these while looking for something unrelated -

Combining the Advantages of Qt Signal/Slots and C# Delegates/Events
http://www.kdedevelopers.org/node/305

Slot classes, which are templates
http://www.allegro.cc/forums/thread/595124

sigslot - C++ Signal/Slot Library
http://sigslot.sourceforge.net/

nroberts
6th January 2011, 06:48
Found these while looking for something unrelated -

Combining the Advantages of Qt Signal/Slots and C# Delegates/Events
http://www.kdedevelopers.org/node/305

This just looks like some sort of proposal.



Slot classes, which are templates
http://www.allegro.cc/forums/thread/595124


This is a very interesting link! I'll have to look at it a bit to see what it's doing. I'm very surprised and skeptical that the connect() line works. It might be for an older version of Qt.



sigslot - C++ Signal/Slot Library
http://sigslot.sourceforge.net/


Yep, I think this was the first C++ only sig/slot mechanism. GTKmm used it but now has its own (dunno why). Eventually something similar ended up in boost. Now there's the signals2 library in boost that is thread safe.

If you haven't started using boost yet, you should.

Thanks for the links.

nroberts
6th January 2011, 19:07
* - bugs need hashing out...

nroberts
7th January 2011, 21:16
Part 3 is back up. Had to peek behind protected access in order to provide type checking. Was looking for a better way. I may have found one that will end up being better for when I solve for non-void returns.

This version uses C++0x stuff. The next part will be even more so.