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.
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.
They got move semantics, smart pointers, concurrency primitives, type deduction, etc. out the door first. While I agree that reflection is important, it's not as important as those. I don't see any problem with comittee's prioritization.
Consider the metric of "damage done by the workaround."
Smart Pointers: have to put explicit refcounting in the root "Object" class
Concurrency Primitives: dependency on the POSIX API and its various "ports."
Type deducion: a few extra keystrokes, a bit of extra ugliness.
Reflection: Duplicate all ivar definitions in several places (if you control all the code) / create a new C++ parser (!) in order to add the feature to the language (if you don't). Also, you have to learn a new MOS every time you work on a different application. Interfacing two MOSes is always a nightmare.
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.
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;
}
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.
};
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.
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"
> 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.
You absolutely can have the same power with less capable language (I consider Qt an extended C++).
Then why we have inheritance and virtual functions in a lot of languages, even though they can be emulated just fine by function pointers in C? Why we need templates when they are just glorified macros? Why we have lambdas, when it is just a syntax sugar for functor in C++? Why some languages offer pattern matching when it is just a bunch of "if" or "switch" under the hood? Why we need async/await, coroutines and generators, when the same functionality can be implemented with POSIX threading?
Because these higher abstractions enable us to write programs with faster speed and less bugs. It is also much easier to reason about program behavior with higher abstractions.
So the argument that one can do the same thing in a less capable language without feature X and hence feature X is pointless is a false one. If you resist the usage of higher abstractions, you can write a large complicated program just fine, but you won't know what you are missing, how programming would be much enjoyable had you realized the full potential of abstraction.
Sure, and this is why I clarified that we weren't missing out in terms of great difficulty as a result of not having moc in other toolkits.
The difference between your C and C++ comparison is that C and C++ are actual languages, that you can compile directly from. moc is not a language, it's a preprocessor bolted on top of C++. It's adds complexity for something that, while it can be useful, is not often so in most workflows. In that regard, I'm sure people could make thousands of C++ preprocessors to add functionality (I would love a more competent macro system and UFCS, myself), but there's a very good reason why we don't.
I have never done GUI programming. However, is it similar to JavaScript and the DOM in a web browser? It seems like it is a similar paradigm. Although, I could be completely wrong.
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.
The transparent queueing is implemented by the Qt library (with QObject/QEventLoop). Technically, queueing does not rely on moc. (moc is needed for implementing signals)
This is a Qt development (i.e. the development of Qt, not with) blog so for their regular audience the reasons for moc existing are probably already well known.
It would be great if we could ditch moc. If you're using Qt without qmake it can be pain in the butt.
CMake has robust moc and Qt build support in general. I have put it through some interesting use cases without issue.
For a simple GUI program, in your CMakeLists.txt, you'd typically want something like:
set(CMAKE_INCLUDE_CURRENT_DIR ON)
set(CMAKE_AUTOMOC ON)
find_package(Qt5Core REQUIRED)
find_package(Qt5Gui REQUIRED)
find_package(Qt5Widgets REQUIRED)
qt5_wrap_ui(UI_HEADERS dialog1.ui dialog2.ui mainwindow.ui)
qt5_add_resources(UI_RESOURCES resources.qrc)
add_executable(simple_program main.cpp dialog1.cpp dialog2.cpp ${UI_HEADERS} ${UI_RESOURCES})
target_link_libraries(simple_program Qt5::Core Qt5::Gui Qt5::Widgets)
Additionally, CMake is the best way I have found to build PyQt5 Python extensions that have C++ Qt bits exposed via PyQt/SIP. A project (of mine) that does this: https://github.com/erikhvatum/RisWidget (MIT license, so feel free to copy and paste anything useful).
Message passing across threads is very easy with boost asio: you just post a callback to the respective io_service. That is effectively what Qt does anyway, but no Qt required.
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?
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.
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.