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.
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.
CERN's ROOT software alleviates some of this issue with their dictionary builder for their own format.
template< class Archive >
void serialize( Archive& ar, POD& pod )
{
ar & pod.field1;
ar & pod.field2;
ar & pod.field3;
} 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.
};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.
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"
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.
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.
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.
moc allowed a nice syntax for signal and slot (invented at a time in which C++ compilers did not support templates). And now it allows QML.
The disadvantages are not as bad as one claims. It's not so hard to integrate moc in any build system.
See the relevant bit from Qt's documentation for more information: http://qt-project.org/doc/qt-5/why-moc.html
It would be great if we could ditch moc. If you're using Qt without qmake it can be pain in the butt.
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).
Similar things can be used for the various event loops.
If you were so inclined, you could write something that uses less dynamic memory allocation.
Now that I read that code, I think I should be moving some of this stuff to C++11, at least WRT rvalue-refs...
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.
Example: http://code.woboq.org/qt5/qtbase/tests/auto/corelib/kernel/q...