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.
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.