Blog of Woboq, a C++ and Qt consultancy, covering Qt internals, moc, C++ reflection, and code browsing tools.
Commenters link it on Qt's moc, signals and slots, and C++ reflection, and point to its Rust and QML work as relevant to Qt.
So this is where I'd start[0].
Their site has amazing documentation. I personally found Qt even in the KDE2 days miles better than React/Redux and non-Smalltalk MVC's. Since then it's only gotten better. Check out the examples here[1], the diving in section here[2], the book here[3], Stackoverflow has an overview of the whole system here[4].
You emit signals. Slots consume them. QObject::connect links the two. Queues are just queues in the traditional MQ sense. You don't use them in for, say, local GUI controls since it's generally a 1-1 unidirectional link (and if it's bi-directional, although I rarely need to do this, just ::connect( a,b,SLOT(),SIGNAL() ) then ::connect( b,a,SLOT(),SIGNAL() ). If you're still having problems read this[5]. If you have issues, that blog also has a preceding page which has a comprehensive analysis of the underpinnings of the entire slot/signal system in QT. If you still have problems, get on IRC and someone will give you a hand. If you're having a major issue, contact me. If it's a quicky I'll lend a hand, if not I know a few absolutely spectacular HN engineers who I'd recommend in a heartbeat.
I'd be real curious as to what's you consider 'messy' about signals/slots is you're having re: slots/signals (I guess since I've used Moose's MOP with Perl 5 and CL they sort of came naturally to me). I have no affiliation with Trolltech/QT/Nokia/whoever-owns-whatever-now at all; I just think C++ is real easy to mess up, libraries are even easier…
With Qt you don't really have to deal with unexpected messages. A signal is triggered by an event, like a button click or a slider value changing, a checkbox being toggled, this kind of thing. A slot is just a place to receive it, it's a regular function or method with a compatible signature for the kind of event it's meant to process. There are no unexpected calls because you have to explicitly connect a signal to a slot, something like:
QObject::connect(&button, &QPushButton::clicked,
&mainWindowController, &MainWindowController::onButtonClicked);
If no slot is connected, the signal just doesn't go anywhere.
Something that's special with Qt is that signals and slots are declared in the class using custom syntax, e.g.
slots:
void onValueChanged(int value);
signals:
void valueChanged(int newValue);
Yes here "signals:" and "slots:" look like the same kind of keyword as "public:" or "private:" in a class declaration, even though internally they're #defined as "public:" and "/**/" respectively.
Qt makes use of a tool called MOC – the Meta Object Compiler – to generate code for signals and slots. It's not a pre-processor but a code generator, which has to run before you can actually compile the code. I think you could probably implement a similar system of event subscriptions without this additional code generation step.
See this page for details: https://woboq.com/blog/how-qt-signals-slots-work.html
> With Qt you get a lot of conveniences and built-in magic, but I'd say at that point it's not really regular C++.
This is a common misconception of beginner Qt users or people who just looked at Qt superficially and decided not to use it, because it's not "regular C++".
You use Qt with 100% pure C++. Qt itself is written in 100% pure C++. The part that confuses people is the metaobject compiler (or MOC). This is a simple code generator tool that provides additional features like runtime type information and reflection. It does not modify your source code, only generates some additiona, 100% legal C++. Granted, this requires an extra build step before invoking the C++ compiler. But Qt's build system handles this automatically, and it's not really difficult to integrate into any other build system.
Starting with Qt 5, you don't even need to invoke the MOC compiler, because in many cases, the features provided with generated code were replaced by new C++11 functionality.
If/when C++ gets proper metaclasses and programmable compile-time code generation, there will be no more need for MOC, because all of its functions can then run in a single compilation step.
There's a great blog post debunking the myths about the QT metaobject compiler - https://woboq.com/blog/moc-myths.html
Rust Qt Binding Generator is for projects that contain Rust and QML or Rust and Qt widgets. The GUI code will be in the native language for Qt: C++ or QML. The data model underneath and any non-UI parts can be written in Rust.
This approach was chosen because it's hard to wrap Qt Widgets (let alone QML) safely in a Rust API. Generating binding code is a very pragmatic approach that works now. You do not need external libraries, just generate some code, include it in your project and use qmake/cmake/... and cargo together.
I've explained this approach in a presentation at FOSDEM [0].
That being said, there might well come a better solution that manages to wrap Qt and the mechanisms of deriving from Qt model classes in a Rust API. It may even manage to require only Cargo as a build tool. In fact, only yesterday Olivier Goffart presented a prototype that does just that. [1] And that project has the exact same to-do application in its examples with only Rust and QML (no JSON or C++).
Switching between those approaches should be very simple though. Especially since Rust has static typing which makes refactoring a breeze.
[0] https://fosdem.org/2018/schedule/event/rust_qt_binding_generator/
[1] https://woboq.com/blog/qmetaobject-from-rust.html
Especially when used in the core/client split version, which allows you to use the webclient https://github.com/magne4000/quassel-webserver/, the irssi-client https://github.com/phhusson/quassel-irssi, the iOS client https://woboq.com/iquassel.html, the Android client https://play.google.com/store/apps/details?id=com.iskrembilen.quasseldroid or https://f-droid.org/packages/com.iskrembilen.quasseldroid/, the new alpha of the new android client https://quasseldroid.info/, and the fulltext search https://github.com/justjanne/quassel-rest-search (with demo here: http://s3.kuschku.de/public/quassel-rest-search.mp4 )
Quassel alone is a kinda nice client, with the entire ecosystem around it, it becomes amazingly powerful.
And the beauty of the Qt client is that, being Qt, you can fully style it with css - e.g. https://bugs.quassel-irc.org/projects/quassel-irc/wiki/Stylesheet_Gallery
Disclaimer: I contribute to some of the above mentioned projects)
10 years ago, in another life, I was already experimenting with trying to provides feature from moc with reflections and from other macros:
- https://woboq.com/blog/reflection-in-cpp-and-qt-moc.html 2014, That was based on a previous reflection proposal
- https://github.com/woboq/verdigris : 2016, Replaces the moc by a set of macros.
What my verdigris experience shows is that it is perfectly possible to replace the moc at the cost of slightly uglier macros. And this was using C++14. I haven't look in details at the C++26 reflection, but I'm sure it would make it easier to make these macro more pretty.