
Can Qt's moc be replaced by C++ reflection? - ingve
http://woboq.com/blog/reflection-in-cpp-and-qt-moc.html
======
jjoonathan
It's nice to see that C++ is finally getting reflection. The real question is
why it took so long: reflection is a killer feature in a large number of
commonly occurring practical settings (GUI creation, user scripting,
serialization, multithreading/IPC) yet it came to C++ relatively late in the
game, to wit, _after_ C++ got a turing-complete template system and _long
after_ grotesque workarounds like Qt's moc grew to maturity and metastasized.
When there are large numbers of people using workarounds ranging from "don't
use C++" (see: desktop frameworks other than Qt) to "implement your own
restricted C++ parser to _add_ reflection" (see: Qt) you would think that
reflection would have found itself higher on the priority list. Is there
someone here who can help me understand why the C++ standards committee had
priorities that were so different from these communities for so long?

Are people making desktop apps, games, and other heavy users of reflection
simply not well represented on the standards committee? Did bikeshedding delay
reflection for a decade? Did language lawyers resist adding it because there
exists a "clever" template-infested strategy for emulating it (at the expense
of using arcane and sinfully ugly syntax in your declarations, naturally)? It
sounds like it could make an interesting case study, but I'd settle for a
tl;dr.

~~~
jordigh
>The real question is why it took so long

Remember one of C++'s promises: if you don't use it, you don't pay for it.
Your C++ programs have to be as fast as C as long as you're not using any
C++-only features. The only way to have reflective information is to add all
of this reflective information to your binary. But when do you add it? How?
Obviously you don't want to add if the calling program never uses reflection,
but it's difficult to predict in advance when this is going to happen. Worse,
what if a program wants to use reflection on a pre-existing external library?

I suppose they're finding ways around this problem, but that's essentially why
it's taken so long. RTTI is expensive enough, and reflection even more so. If
you want polymorphism in your reflection (and reflection seems kind of useless
to me without it) I don't think you can do all reflection at compile time, so
some sort of payment will have to be done at runtime.

I suppose non-polymorphic reflection is enough for Qt, but it's still a very
limited form of what is usually desired from a reflective interface.

~~~
Leszek
You're confusing compile-time reflection (what is needed for moc) with runtime
reflection (which affects binary size and execution time).

------
saboot
Another similar use for reflection I am waiting for is a way to effortlessly
serialize data. Specifically for physics experiments I have several PODs from
different acquisition devices. Instead of serializing them all myself, it
would be great to just pass them onto a function to do that for me. Also
useful because people will inevitably ask "I don't like file format <X>, can
you save it as <Y>?".

CERN's ROOT software alleviates some of this issue with their dictionary
builder for their own format.

~~~
stinos
Thing is if you go somewhat further than POD you always end up with 'this
field should not be serialized' situations so you'd still have to manually add
code to indicate that. Though I agree it would be nice just be able to tell
'serialize this struct', it's not really that hard with boost.serialization or
similar to declare the serialization functions manually (I don't know how ROOT
does it):

    
    
        template< class Archive >
        void serialize( Archive& ar, POD& pod )
        {
          ar & pod.field1;
          ar & pod.field2;
          ar & pod.field3;
        }

~~~
cozzyd
ROOT does this with its own preprocessor and custom comment decorators. like:

    
    
        class mydata
       {
           
            /* simple type */
            int n; 
    
           /* the following array is of length n */
            double  * v; //[n]       
    
          /* don't serialize the following */ 
          int reference_count; //! 
    
         ClassDef(mydata,1) ; // this macro does some magic, 1 is the version number etc.
       };

~~~
stinos
Didn't know that. But after seeing this: I _vastly_ prefer a streams based
orientation then. No magic, no comments.

------
byuu
I've never doubted that moc does things that C++ itself can't.

My objection to moc has always been that it does things I flat out don't
_need_ in GUI design. I mean, there's a whole world of Win32 and GTK+
applications that get by just fine with specifying callback functions; and
it's not as though they are suffering and in need of moc-like functionality.
And now with C++11 lambdas, it's an absolute breeze: button.onClick([&] {
printf("clicked!\n"); });

Certainly, Qt does a lot more than just GUI stuff, and there are use cases
beyond my own. What immediately springs to mind is using callbacks within
QtScript, or perhaps some integration with QtQuick.

But the annoying part is the way that you _need_ to run your headers through
moc (and this often dovetails into "replace make with qmake", which is even
more extreme) in order to use Qt. I think most, if not all, of the objections
over moc would go away if they made the moc component optional to those who
want the extra power.

~~~
prewett
Qt started long before C++11, as I'm sure you know, and lambdas weren't
available for the 10 years prior. The big advantage of the MOC from my
perspective is the signals and slots. Sure, most of the buttons are just a
callback. But there are times when something in the UI needs to change based
on another piece of the UI. With signals and slots, neither object needs to
know about each other, the function creating them connects the signals. So you
can connect(togglableMenuItem, enabled(), uiObject, setEnabled()); and with
one line of (pseudo-ish) code, when you toggle to menu item, the object will
be enabled and greyed out, as appropriate.

You can do this with callback objects, but it's kind of clunky if the pieces
of the UI that need to communicate are far apart in the widget hierarchy. The
worst is if you need to notify a component inside a widget (or several levels
down); then you have to pass the object all the way down. Or you can go with
something like Java's observer pattern, which from my experience is a whole
lot of annoying boiler-plate which the MOC avoids.

You only need to run headers of QObjects through MOC, although that is most of
them if you are using Qt, obviously. I tend to prefer qmake over make, as you
don't have to deal with non-GNU make on Solaris, AIX, etc., although that is
less of a feature these days. (QMake on Windows is not too fun, but I try to
avoid using Windows in the first place.) It is also really easy to add pieces
of Qt without needing to remember what libraries you need to add. Need OpenGL?
"QT += gl" (or something like that) Want the optimized version on all
platforms? "QT += release"

~~~
byuu
> Qt started long before C++11, as I'm sure you know, and lambdas weren't
> available for the 10 years prior.

Of course. That's also the reason we have UTF-16 and a Qt reimplementation of
the standard library: the project's age and need for backward compatibility.

moc for C++98 didn't offer closures, so you still had to write a separate
function and then call connect() to link the signal with the new slot
function. Even in C++98, moc could have instead just allowed you to use a
version of std::function, written for C++98 (I wrote such a container, as did
boost.) So instead you'd have: button.onClick(&MyClass::clickEvent,
&myClassObject); which for at least 98% of GUI programming, would cover the
same use case as connect(button, SIGNAL(pressed()), &myClassObject,
SLOT(clickEvent())); but without the need for preprocessing; and without the
downside of run-time type checking of the signal and slot names.

...

I definitely don't doubt you that you have use cases that moc makes
significantly easier. But in my case, I really don't. And I've written a dozen
simple to moderately complex UI applications. So, I would be appreciative if
in my simple case, I didn't have to use moc at all.

One thing I do like, that is possible with a fancier std::function class, but
is still kind of clunky with pure C++, is the way you can bind a slot that has
less parameters than a function ordinarily takes. It's a nice way to offer
additional information, but not require you to have an exactly matching
callback signature. Great for binding multiple signals to the same generic
slot that handles all cases at once (eg "synchronize()" called whenever you
change a setting.)

> You only need to run headers of QObjects through MOC, although that is most
> of them if you are using Qt, obviously.

Yeah, I wrote a recursive wildcard search function in GNU make to find all
files that matched "%.moc.hpp", and then ran moc against all of the results.
It's not a huge burden, but it's still kind of annoying. It interferes when
you just want to write a small utility class and have your interface and
implementation in the same file. You have to deal with knowing what moc is
called (moc on most platforms, moc-qt4 on Debian). You can't distribute pre-
parsed moc files because they are _extremely_ version-dependent.

> I tend to prefer qmake over make

I prefer GNU make over qmake, bsdmake et al. qmake is great if you like it,
but not if you're already happy with your build environment, use lots of
specific features from your build tool, and don't want to change it just to
make using Qt easier.

------
plq
Qt's meta object compiler (moc, a code generator that lets C++ kind of emulate
Objective-C's message passing) is mighty handy for transparently queuing
(instead of directly calling) signals that cross thread boundaries. I don't
see anything in this post that mentions it.

See the relevant bit from Qt's documentation for more information: [http://qt-
project.org/doc/qt-5/why-moc.html](http://qt-project.org/doc/qt-5/why-
moc.html)

~~~
72deluxe
wxWidgets has QueueEvent and ProcessEvent and AddPendingEvent for this sort of
thing - does Qt force you to emit a signal without being able to queue it
first?

~~~
ehvatum
Qt offers both signals/slots and a lower level (but still cross platform)
event system with the usual post event (async) and send event (blocking)
methods.

Signals/slots provide a connection abstraction on top of events, and blocking
vs queued behavior is a per-connection attribute. So, in cases where the
emitter wants to control blocking vs async behavior, you might use the event
system with post or send directly.

