(Andi Peredri kindly provided a russian translation for this article.)

On gtkmm and Qt (again)

(and, let's hope, for the last time).
In this interview, Murray Cumming, the current maintainer of gtkmm (formerly known as Gtk--), talks about me, why he thinks I left gtkmm, and the advantages of gtkmm over Qt. Given that I disagree with pretty much everything he says, I feel I should answer.

Why I left

Murray : (...)My guess is that Guillaume never really got a handle on the gtkmm codebase and took the opportunity to jump clear of something that daunted him. (...)

I explained why I left gtkmm, and no, "the opportunity to jump clear" wasn't among the reasons. You are almost right on one thing though. I indeed never really got a handle on the gtkmm internals, because they were Karl's realm, I had much less spare time to spend on gtkmm than Karl, and most of all I wasn't interested. My goal was to have a toolkit which we could use for Rosegarden. So my main activity with gtkmm was to wrap widgets.

gtkmm and Inti

Murray : (...)I believe Guillaume felt certain anyway that, with RedHat's backing, Inti would succeed and gtkmm would fade away.

Well yes, I believed Inti would succeed, and obviously I was wrong. The reason I believed so is that, generally, when a developper can work full time on a project, that project moves ahead. But that didn't happen, because Havoc eventually spent most of its time on GTK+ 2.

Murray : (...) Most gtkmm users and developers strongly disagreed with Inti's design decisions

As far as I know, "most" here means about half a dozen people or so, according to the threads I could read in the archives. The main one was obviously Karl, whose point of view I still totally disagree with. I didn't need a "hacker toolkit", I wanted a toolkit that was working and easy to use.

Community development

Murray : (...)Inti died because it never involved a community of hackers(...)
(...)Basically, QT isn't developed publicly so it makes a number of mistakes without the benefit of any real criticism.(...) And perhaps most importantly, if you find a problem with gtkmm you can submit a patch or discuss it with the developers.

As I said, I think it's more likely that Inti died because its maintainer stopped working on it. As for Qt, indeed it is not developed publicly, and guess what : that's good.

You seem to imply that public development means quality. This is an old Free Software myth. Emails exchanged in their spare time by people who think they know what they're talking about (and I certainly was one of them) doesn't guarantee anything. But a small team of skilled people who work every day on the problem, receive user feedback, and who can discuss around a table stands a fairly good chance to achieve something good.

Let's face it : good programmers aren't dime a dozen, even in the Free Software world. Although the difference is that many less realize what their actual skill level is. So involving many people in decisions on tough problems doesn't help, it makes things worse.

All gtkmm design decision were publicly discussed at length, and some were still wrong (like the memory management issue) mainly because none of the people involved in the discussion was actually using gtkmm to create an actual application. We were all too obsessed about creating a "real C++ API", not about making something convenient to use. Karl's post which I linked above is the perfect example of this. This weblog entry by Matthew Thomas, which was heavily discussed in on many sites, hits the nail right on the head. It talks about UI design, but most points apply to API design too. Be it for Users or Programmers, Interface design yields the same kind of problems : balancing standards, aesthetics, and pragmatism.

So the reason Qt is good is because Trolltech's developers are talented, and they do listen to their customers (I know that first hand because I was one of them). And their customers are creating large, real-world applications. Their customers don't care about "being faithful to the C++ spirit", they care about solving real problems and gettings things done. Qt's developers don't try to second-guess what is a good API and what isn't, they have about 2000 customers confronting their choices to reality.

I'm not saying Qt's API is perfect, it does have some quirks. I'm saying that it works very well, and the reason I say so is because I've been using daily for the past two years, on two different project (Rosegarden and a in-house development for my previous employer). You'll have a hard time creating something better, and I don't believe gtkmm is going in that direction, quite the opposite.

And finally, you can submit a patch to Qt's developers, and discuss problems with them, because customer support is part of their job. I know that first hand because I've done it myself, and so are KDE's developers.

Qt's "extensions" to C++

Murray : (...)Chief among these is its modification of the C++ language and the use of its own non-standard string class. It isn't necessary, as we've proved.

Regarding QString, it is undoubtedly necessary because std::string doesn't handle Unicode. gtkmm itself has Glib::ustring, I see that you made its interface similar to std::string, and I also think it's a bad idea, because no matter how standard it is, it's not very convenient nor powerful. QString offers very useful features like arg(), sprintf(), section(), simplifyWhiteSpace(), toInt() and its siblings, setNum(), and of course regexp support, which are invaluable in everyday development.

Now about these ever controversial modifications of the C++ language. You argue that they aren't necessary. It's true, although you haven't proven it quite totally because gtkmm doesn't provide all the features Qt's "extensions" do.

Signals and slots

I'm specifically thinking of how slot and signals are handled as symbols. In gtkmm, they are template functions and that's what you pass to your connect call. In Qt they are good old const char*s. Shock ! Horror ! QObject::connect takes const char* for slot and signal names ! That was my initial reaction too. Then later on I realized two things :

That second point was most important to me. It saved me weeks of development for that in-house application I was developing. The application was generating its UI at startup from an XML description file, and in that file I could encode things like
      <connect source="widgetname" dest="someclass"
	       signal="buttonPressed()" slot="receivedButtonPress()" />
    
and the code to handle that was done in half a day. And right now, I believe this is being used in Qt Designer. Try doing this with libSigC, see how "easy" it is.

Another thing this dynamicity brings is loose coupling. That is, when you're calling connect you don't need to have the full type and definition of neither the source and destination type. You just need to know that they are QObjects. Therefore in the cases (like the one I describe above) where the connection is made elsewhere in the code than in a method from the source or destination, the function doing it doesn't need to #include the definitions of source and destination. It can just be

      void do_connect(QObject *source, QObject *destination)
      {
          QObject::connect(source, SIGNAL(buttonClicked()),
                           destination, SLOT(gotButtonClicked()));
      }
    
Yes, you lose type checking at compile-time (but you still have it at runtime - you get a warning message if connect() failed), you won't get a compile error if the source or destination don't have the right signal or slot in their definition, but in practice it still lets you get things done faster.

And this kind of design (where the connection between two objects is done by a 3rd one) is very common. Once you realise that signals aren't just for event processing but also let objects communicating with one another while remaining loosly coupled, you'll do it quite often.

Even if the connection is established by the source or the destination, you still win. You can have

        void MyWidget::do_connect(QObject *destination)
        {
          connect(this, SLOT(itemClicked(int)),
                  destination, SLOT(gotItemClicked(int)));
        }
      
You're not tied to the definition of the destination, which you're free to refactor and change. Again a big development gain. Why do you think all newly created languages like Java or C# have this same kind of flexibility ? It just lets you work faster. In these two years where I've been using Qt, I don't recall ever being seriously bothered by a slot/signal related bug. I used to think this lack of type checking would come back and bite you, but it doesn't. The warning messages are enough to track the problems efficiently.

More information on the subject can be found in Qt's documentation.

moc and added keywords

This is the most often brought up argument against Qt. These 'slots', 'signals', 'emit' which you have to use in your class definitions and code aren't C++, and you can do without. Yes, it's true. But the fact is that you do better with them. They make your code clearer and easier to read.

Trolltech already provides a very good explanation on why Qt doesn't use templates for signals and slots, which I think I've already pointed you to. Again, I've verified each of the points they make through my own experience, as have, I believe, all Qt users.

It's ironic though that one of their point is that syntax matters. As you've been wrapping the "OO in C" API of GTK+ & Co., you, more than most, know how much this is true. And yet you're displaying the same behavior as the people who think that OO is merely syntactic sugar. Well, just like classes, signals and slots are well-defined concepts, and therefore it makes sense to implement them at the language level (in that case, so to speak), rather than letting the user alone deal with them.

So your solution to the slot/signal problem is to do them all with the current facilities of C++, just like others are doing classes in C. My solution is to bite the bullet and make 'slot' and 'signals' official C++ keywords :-). The internals can be a C++ library or machine language, that's not important. What matters is that you get added facilities to express your design to the language.

Regarding the usage of moc itself, it is, again in my experience, not a problem. If you're doing your own makefiles, it's one more line to add and you're done with it. Otherwise, KDE's automake macros or Qt's qmake handle the problem for you. It practically never gets in your way.

Murray : (...)It's then easier to use gtkmm in combination with other C++ APIs.(...)

What problems do you see with the use of Qt in combination with other C++ APIs ? In Rosegarden we're happily using the STL (and quite a lot) with absolutely no problems, except those caused by the tricky part of the STL itself :-). For example std::vector<QString> works as expected.

Murray : (...) I believe that you'll love gtkmm if you love C++, and that gtkmm is a better role-model if you're learning C++. (...)

I'm not sure about gtkmm being a "better role-model" for C++ students, but your saying "you'll love gtkmm if you love C++" is the core of the problem, and the reason you still fail to understand why Qt is better. I don't love C++. I don't care about C++. I care about writing applications that do useful things. So I don't mind using a library which adds non standard keywords to C++, as long as it helps development. But you care for C++, so you can't do this. You care up to the point where you're oblivious of its flaws, and you don't realize that by trying to remain "faithful" to it, you make your life harder, not easier. Again, this is exactly how Gnome's C hackers happily handle the GTK+ Object System, not realizing that they could achieve the same things so much faster using C++ and Qt, and utterly convinced that what they do is "easy", because they love C and they don't need to learn another language.

Standards aren't sacred things. Theoretically you'll be better off following them, but in practice it's not always the case, simply because they were devised by fallible humans. And tools or languages shouldn't be loved, they should be used appropriately. Otherwise, when a better alternative comes around you'll ignore it, because you don't want to give up your own precious one.

Qt vs. gtkmm

While I'm at it, I'd like to address some of the other points you made during your GUADEC talk.

data containers

You say : QT duplicates a lot of stuff that is now in the standard library, such as containers and type information.

This is true. But :

Memory management

Ah, that old horse again. First of all, you say that Qt demands pointers, and this is false. You can use regular variables for widgets (see this example), and if you're using pointers you can delete them yourself. The thing is, generally you just don't want to.

Suppose you create a fairly complex dialog class with lots of controls and labels. You obviously need to keep track of the controls because you'll need to know their status, so you keep them as data members. But what about the labels, and the layout widgets ? What is the point of keeping around a reference to them ? Isn't it easier to just

        new QLabel("Some label here", vbox);
      
and forget about it, because you know Qt will handle the deletion for you ? As far as I'm concerned, yes, it is easier. There's no glory in doing your own memory management when you can let the machine do it for you. It will always do a better job than you anyway.

So you claim that leaving the user the possibility to do something tedious and error-prone is a good thing, because it's among "normal C++ choices". I claim that these "normal C++ choices" should be hidden by any good C++ library. Do std::string and all STL containers bother you with how they allocate memory ? They don't. At best you can use your own allocators, because sometimes you can have very specific requirements, but this doesn't apply to widgets. So why should Qt be any different ?

container widgets

In your talk you say that Qt's containers and layout classes are seperate, as opposed to gtkmm's choice of containers. I'm not sure I understand your point. Qt has containers widgets like QVBox, just like gtkmm has VBox, and which behave quite the same (you just add widgets to them, in the case of Qt that means creating new widgets when the QVBox as parent, no explicit "add" needed). In addition, Qt has layout classes, which let you perform more fine-tuned layout management (like QGridLayout, which offers more options than its "easier" counterpart QGrid). And you can, of course, create your own layout classes if you have to.

So in that case Qt clearly offers the same features as gtkmm, and then some. Hence my not understanding your point.

Learning and using

We think that gtkmm makes your code clearer and more consistent. We think it gives you less to learn and less to worry about.

My own experience directly contradicts this. Two weeks after taking on Qt, I was more proficient with it than I ever was with gtkmm, and I worked on the damn thing for about three years :-).

In the course of the past two years I also discussed with half a dozen "former gtkmm users", which had all switched to Qt or Swing, or even plain GTK+, and all told me the same : gtkmm is too complicated and too heavy to use. I trust you've improved the API with gtkmm2, but what you can't help is the chore of dealing with yet another bunch of libraries in your setup. I also wonder why Terraform which at the time was about the only large application to use gtkmm, no longer does.

So let me again refer to my own experience with Qt, which as far as I can tell is a pretty common one : all these non-GUI related classes that Qt has, like an XML parser, thread handling classes, date and time handling, regexps, etc... are very useful. They're not here because Qt's developers thought they were fancy, they're here because Qt customers asked for them, and they did so because they needed them. You won't write a modern desktop application without using these features. Rosegarden uses gzipped XML as a file format. XML was an obvious choice, mostly because Qt has a parser for it. To do the same with gtkmm, we'd need to link with libxml. That would be yet another library to deal with, with a different API, more or less documented, etc... we might even need to wrap it, and that would yield even more code.

And this in fact exactly represents my feeble attempts at working on Rosegarden using gtkmm (see the Rosegarden development history for more details). I first tried to create a simple widget to display notes on. But wait, I have to create note pixmaps on the fly and to do this I have to use GDK and imlib, neither of which were totally wrapped at the time (and the wrapper was using a completely different memory management policy than the rest of gtkmm). So I first had to add stuff to these wrappers. Then I needed the Gnome Canvas to display staff lines and notes on. Not fully wrapped either, so wrap it. And so on, ad nauseam. Today it would be just the same with libxml, vfs, and all the facilities we use that KDE provides but which Gnome equivalents you haven't wrapped yet (and I use "equivalents" loosely).

The bottom line is that about a month after switching to Qt/KDE, I had made more progress than in the past 3 years. Some time afterwards, Chris and Rich joined back and now we're still making constant progress, because the framework doesn't get in the way, not even for fairly hard things like IPC. DCOP works just great, it took me 20 mns (I'm not making this up) starting from not even knowing what to do, to having Rosegarden reacting to DCOP messages. Most UI questions are solved within hours, and we can concentrate on the actual problems. A while ago I threw some disorganised thoughts about Rosegarden development, which you can refer to if you need more details.

About "learning less", looking at the gtkmm's docs I see this page on memory management. Contrast with the Qt equivalent.

Conclusion

Murray : (...)Guillaume uses QT now. He has stated that it was more important for him to have a full working toolkit than a perfect API. gtkmm2 will go stable soon - then we will have both in one toolkit.

Yes, I use Qt/KDE, and am happy about it because after all these years Rosegarden is starting to look like a real application, which has always been the point. It would never have happened with gtkmm.

Contrary to what you say, gtkmm2 is years away from providing the same level of features. And when it does, if ever, it will be at huge ressource costs because you'll have to carry every lib plus its wrapper. Even with gtkmm, gnomemm, bonobomm (which underneath imply linking with all the Gnome libs they wrap), you still don't have all the features of Qt and kdelibs. Looking at the hierarchy of a simple widget, I count 4 underlying "objects" :

One has to wonder about the memory impact of these.

Another question is, even though gtkmm has been stable for several years now, why are there still so few applications using it ?

We had a similar discussion about a year ago. As it seems, your point hasn't changed : you don't like Qt, matter of taste, but you still have no precise arguments as to why using it would make your code hard to write and maintain. My experience is that Qt makes writing and maintaining code an easy task. Just look at the wealth of software it generated. If gtkmm is ever used as widely, then you'll have a point. This is Free Software, so the better technology should prevail, right ?

You don't like Qt because it doesn't fit your idea of what a C++ library should be, that's all. I think your idea is wrong, and that gtkmm repeats exactly the same kind of mistakes which earned C++ a reputation of being a hard and error-prone language : not specifying enough and leaving too many things up to the user.

So I wish you good luck with gtkmm2, but I'll continue on using Qt/KDE and help Rich and Chris with Rosegarden.


P.S. : a "patch" for gtkmm FAQ #2.4

These are fixes to the answers on some the items.

Guillaume Laurent
Last modified: Wed Jul 28 23:46:07 CEST 2004