Kuro5hin.org: technology and culture, from the trenches
create account | help/FAQ | contact | links | search | IRC | site news
[ Everything | Diaries | Technology | Science | Culture | Politics | Media | News | Internet | Op-Ed | Fiction | Meta | MLP ]
We need your support: buy an ad | premium membership

[P]
More Qt

By e8johan in Technology
Wed Mar 19, 2003 at 01:15:31 PM EST
Tags: Software (all tags)
Software

Qt is known as a cross platform graphical user interface toolkit. This is true, it is a great cross platform GUI toolkit. But! It is also a cross platform toolkit concerning databases, file access, sockets and much more. This article concerns the Qt object model and why this is an improvement over the classic C++ model.


The Qt Object Model

The classic C++ object model has data and methods that either can be private, protected of public. When designing a GUI (or any other event driven task) we want to tie a method implemented by us to a specific event. To do this, we inherit the event generating class and overload the virtual method and re-implement it to do what we want it to. This gives us two problems: a) we will have a new class for each action and b) if there where any functionality in the original, virtual, method, we will have to re-implement it or make an explicit call to the original function.

Qt solves this problem by introducing signals and slots. A method can be defined as a slot that is either private, protected or public. Slots are ordinary methods, but they are listed in the slot table of the meta object. Each class utilizing the Qt object model has an automatically generated meta object containing type information, inheritance information and a list of signals, slots and properties.

A signal is declared as if it was a usual method, but it may not be implemented. Signals cannot be called but emitted. Let us go back to the event driven GUI example. Instead of inheriting the event generating class we implement a slot that fits the signal emitted at the interesting event.

There are more packages based on signals and slots such as GTK+ and Boost.Signals. These are not dealt with in this text. If you intend to work with this concept in your projects I recommend you to check these alternatives out too. My personal opinion is that GTK+ fails by being implemented in C and Boost.Signals do not offer GUI components and thus falls outside my current application.

A Code Example

Let us demonstrate this by looking at a small example. We will put two buttons in a dialog and let them alter the text of the title bar. We start with a version using the inheritance method, after that, the Qt version is discussed.

The Inheritance Version

We start of by looking at our imaginary button class. It holds a lot more than the stuff that is shown here, but this shows the idea.

class Button : public Widget
{
public:
Button( char *label , Widget *parent=0 );
Button( Widget *parent=0 );
~Button();
...
protected:
// Replace these methods to respond to events
virtual void eventClicked( void );
...
};

This class is fairly straight forward to use. Simply inherit it and replace the virtual methods of your choice to respond to events. We can also assume that the layout management of our imaginary toolkit uses a Qt-like approach, so that we simply supply a parent and things work by them selfs. We also assume that the toolkit takes care of memory management just as Qt, i.e. when the parent is deleted, any children are deleted too.

Now we create our dialog though inhertitance from our imaginary toolkit.

class Example1Dialog : public Dialog
{
public:
Example1Dialog();
};

Before we can implement the constructor we will need to create our buttons. These buttons contain the actions that is needed to change the title of the dialog.

class FooButton : public Button
{
public:
FooButton( Dialog *parent ) : Button( "Foo", parent ) {}
protected:
void eventClicked( void ) { parent->setCaption( "Foo" ); }
};
class BarButton : public Button
{
public:
BarButton( Dialog *parent ) : Button( "Bar", parent ) {}
protected:
void eventClicked( void ) { parent->setCaption( "Bar" ); }
};

I changed the parent type to only accept dialogs, just to be on the safe side as we call the parent when we recieve an event. Nothing too complex this far and the implementation of the dialog constructor is not too hard either.

Example1Dialog() : Dialog()
{
setCaption( "Click!" );

FooButton *fb = new FooButton( this );
BarButton *bb = new BarButton( this );
}

Notice that I have left out any layout related code. This version is a bit simplified, but so is all code throughout this example.

So what are the drawbacks of this version you may ask? One point is that we will end up with lots of classes. Another, more serious, is that the functionality for the dialog (changing the title from user actions) is spread though two classes (not counting the dialog itself). This makes it harder to overview the code and thus it is harder to maintain it. Before drawing any final conclusions, let us continue with the Qt solution.

The Qt Version

As opposed to the previous example we will let the functionality, i.e. the slots, be a part of our dialog and simply connect the "clicked" signals from the buttons to the appropriate slots.

This example covers a fully working example. Remember this when comparing it to the previous example which just showed the highlights.

We begin by looking at the main function that simply initializes the application. It is very simple and should not pose any problems.

#include "example1dialog.h"

int main( int argc, char** argv )
{
// Initialize Qt
QApplication app( argc, argv );

// Create an instance of our dialog
example1Dialog dialog( 0, 0, TRUE );
// Set it as the main widget (as we do not have a main window)
app.setMainWidget(&dialog);

// Execute
dialog.exec();

return 0;
}

Notice that Qt is accompanied by a great documentation set that you can refer if you want to know any details. It is available on-line from http://doc.trolltech.com and contains reference material, examples and in-depth tutorials. In this tutorial I use the free 2.3 version for win32 just to demonstrate that the Windows version is freely available too. The code I present here is fully compatible with any UNIX or Mac version of Qt (it is, as I mentioned, a cross platform toolkit).

Now, we can continue by looking at the class declaration of the example1Dialog class. This is where the Qt object model enters.

class example1Dialog : public QDialog
{
Q_OBJECT

public:
example1Dialog( QWidget* parent = 0, const char* name = 0, bool modal = FALSE, WFlags f = 0 );

protected slots:
void fooClicked( void );
void barClicked( void );
};

First, notice that we inherit a descendant of QObject. This is necessary as the QObject class holds much of the object model functionality. The first line in the actual body of the class declaration must be Q_OBJECT. This macro has two purposes. It declares the things needed to get the object model running and works as a marker that the meta object compiler triggers on (more about this later).

The slots are declared in a pretty intuit way. Signals are declared in a similar way but in the signals: section of the declaration.

We continue by looking at the implementation of the slots:

void example1Dialog::fooClicked()
{
setCaption( "Foo" );
}

void example1Dialog::barClicked()
{
setCaption( "Bar" );
}

This is pretty straight forward as slots are simply ordinary methods that can be connected to signals. As these calls are made from inside a descendant of a QDialog we can set the caption as easily as shown in the code. We can also activate these slots from any signal, not just the buttons as we intend to do in this example.

We will now show the method that takes care of the setting up; the implementation of the creator of our example1Dialog class. This method creates a layout, the buttons and sets up the connections between the signals and the slots.

example1Dialog::example1Dialog( QWidget* parent, const char* name, bool modal, WFlags f ) : QDialog( parent, name, modal, f )
{
setCaption( "Click!" );

// The layout
QVBoxLayout *vb = new QVBoxLayout( this, 8 );
vb->setAutoAdd( vb );

// The buttons
QPushButton *pbFoo = new QPushButton( "Foo", this );
QPushButton *pbBar = new QPushButton( "Bar", this );

// The connections
connect( pbFoo, SIGNAL(clicked()), this, SLOT(fooClicked()) );
connect( pbBar, SIGNAL(clicked()), this, SLOT(barClicked()) );
}

The layout is created with a spacing of eight pixels margin between the edges and each widget. The call to setAutoAdd means that all widgets created with example1Dialog as a parent automatically will be inserted into the layout.

The buttons are created with a text and the dialog as the parent. This means that Qt will delete them from memory the moment that the dialog is deleted. Thus we do not need to care about any complex memory management issues. Each parent will take care of its children through the QObject heritage.

The last thing that we do is setting up the connections. This is where the magic takes place. Here we connect each of the button's clicked signals to the slots that we created. Notice that one can send parameters between signals and slots without (almost) any restrictions. No need to declare special POD (plain old data) classes to carry any parameters, just emit the signals and do not bother.

This version embedds the functionality into the dialog. The signals activating the slots can come from anywhere (think toolbars, menus, keyboard short-cuts, etc. doing the same thing). This does not only have the advantage that all code that affects the dialog is in the dialog class, but the code is more reuseable. Just imagine adding the ability to activate the same functions from a menu. In the Qt code, we just add and connect two menu items while in the inheritance example we will need (at least) two more classes.

The Meta Object Compiler

If you try to compile the code above you will run into problems. The tool that is needed is the meta object compiler, the moc. It creates code for signals and the meta object of the class. You might think that this is an "ugly" solution. This is actually the most common objection to using Qt. However, I have never, during three years of usage run into any serious problems caused by the moc or the object model. If I encounter any problems due to the moc or object model they are always easily solved thanks to good documentation and good debugging support. The biggest benefit, however, is the syntactical clarity that the moc provides. Anyone who knows C++ will be able to read and understand code with signals and slots after just 1-2 minutes of introduction.

The output from the moc will be stored in the file moc_example1dialog.cpp. Simply include this file in your make file and you are ready to go!

qmake

From version 3.0 Qt is shipped with the qmake tool. This completely removes the Makefile hell that Qt could lead to in earlier version. A project file (.pro) is translated into a proper Makefile by qmake. For our example the project file would look something like the file below.

SOURCES = main.cpp example1dialog.cpp
HEADERS = example1dialog.h
CONFIG += qt want_on release

As you can see, the need to explicitly handle the moc_*.cpp files is removed. Do not let the simplicity of this example fool you; qmake is a powerful tool that can handle pretty much all the things that a Makefile can do. By doing fine tuning qmake can even handle platform differences in, for example, third part support libraries.

If you choose to develop your applications using the Qt Designer, you will end up getting the project file for free too. You simply draw the interface (as in Kylix or VB), declare and implement the slots, graphically connect the signals to the slots and compile. Using Designer is really the way to design and implement applications. The example above is just an example focusing on the object model behind.

Conclusions

Qt offers an extended object model that makes it easier to reuse code. The object model introduces new syntax elements that and a new compilation stage (the moc). To remove the introduced complexity Qt also supply the qmake tool that makes it easier than before to build projects.

The syntax of Qt extended code integrates nicely with C++ and makes the code readable and easy to understand. The extensions are transparent to the programmer and does not introduce any new things to think about more than inheriting QObject or any of its descendants and including the Q_OBJECT macro first in the class declaration.

This text does not cover much of the capabilities of the Qt object model or Qt. Worth mentioning is that the object model introduces supports for named properties and lots of run-time information. By using Qt Scripting for Application (QSA) Qt objects can be scripted in JavaScript.

As always when discussing Qt, there is the licensing issue. Qt is available as GPL for the X11/UNIX target. For Windows (win32) the older version 2.3 is available for free software. This is a decision made by Trolltech and it helps them saving money.

The Author

Johan Thelin has a degree in electrical engineering and has worked as a software developer since 1995. He lives in a town just outside Gothenburg, Sweden. His interests spread the whole software spectrum from database design to low level operating system hacking and he has professional experience from both areas and many in between. He has also an interest in hardware design and has implemented a 32-bit pipelined RISC CPU in an FPGA.

Sponsors

Voxel dot net
o Managed Hosting
o VoxCAST Content Delivery
o Raw Infrastructure

Login

Related Links
o GTK+
o Boost.Sign als
o http://doc .trolltech.com
o Also by e8johan


Display: Sort:
More Qt | 51 comments (32 topical, 19 editorial, 0 hidden)
And it's much better then borland! (3.00 / 1) (#3)
by xtral on Wed Mar 19, 2003 at 08:23:54 AM EST

nr

why? (none / 0) (#35)
by illuzion on Wed Mar 19, 2003 at 11:52:09 PM EST

Serious question... I use Borland products, I love them. I've never used qt though. So, can you tell me.. why is qt better? what makes it better than, say, Delphi?

[ Parent ]
Borland uses QT (5.00 / 1) (#37)
by Einar on Thu Mar 20, 2003 at 04:35:18 AM EST

Borland is an investor in TrollTech, the makers of QT. Borland uses QT under the hood in its Linux products, I really don't think Borland vs. QT is a particularly interesting comparison.

[ Parent ]
vs Delphi ? (none / 0) (#42)
by bluebird on Sun Mar 23, 2003 at 06:17:36 AM EST

I'm not a user of Delphi but you can consider the following points:
  • Qt runs on every unix out there, every windows since windows 95, MacOs X and on embedded platform. So this is the best platform-independant choice.
  • Qt is C++. Can be seen as a drawback or as an advantage. After using Qt for a long time, I think it makes C++ a lot simpler to use.
  • Qt is available under GPL on Unix platforms. There is a port of the GPL version to windows going on (http://kde-cygwin.sourceforge.net)
  • Qt is extensible: you can now use javascript to script your qt application. There is also an excellent python binding.
  • integration with existing toolkits: recent version of Qt allow you to develop or use ActiveX under windows, or motif widgets under unix. This is damn cool when  you are porting an old application to Qt.
Globally, you will find more or less the same features in Delphi and Qt. It is hard to provide something revolutionnary new in the field of graphical toolkits today.

[ Parent ]
Interesting, but I'm skeptical (4.50 / 4) (#6)
by twistedfirestarter on Wed Mar 19, 2003 at 08:51:16 AM EST

My first impression is that using a meta-compiler seems to be like using elephant gun to kill a fly.

So what are the drawbacks of this version you may ask? One point is that we will end up with lots of classes. Another, more serious, is that the functionality for the dialog (changing the title from user actions) is spread though two classes (not counting the dialog itself). This makes it harder to overview the code and thus it is harder to maintain it. Before drawing any final conclusions, let us continue with the Qt solution.

I don't really see either of these as serious drawbacks.

You can have lots of classes in the same file, and you can have as many classes as you need. I typically declare entirely new classes just as the return type from a single function. And by keeping the classes in the same files and headers or by using inner classes, you can keep related code together.

It seems to me, to introduce such a complex mechanism as a meta-compiler, there must be better advantages than less classes and improved code layout.

Also, is debugging problematic? Templates, to take another example of metaprogramming, are nearly impossible to debug. Do classes compiled with Q_OBJECT appear befunged, or have strange members?

(BTW +1, technology! A much needed breath of fresh air <gasps>)

A few odd members (none / 0) (#7)
by Ranieri on Wed Mar 19, 2003 at 08:55:18 AM EST

But otherwise rather well debuggable.
--
Taste cold steel, feeble cannon restraint rope!
[ Parent ]
Elephant guns (none / 0) (#49)
by Brandybuck on Mon Mar 31, 2003 at 05:48:30 PM EST

My first impression is that using a meta-compiler seems to be like using elephant gun to kill a fly.

Actually, it's more like using a squirrel gun to kill a squirrel. It's still overkill if you want to kill a fly, but it's the best thing for squirrels.

[ Parent ]

extending the object model (5.00 / 2) (#17)
by tps12 on Wed Mar 19, 2003 at 09:22:25 AM EST

I'm not sure that, in the absence of syntax supporting signals and slots, inheritance would be required to manage events and callbacks. The two benefits of signals and slots seem to be that 1. callbacks are connected to events on a per-object (as opposed to per-class) basis and 2. errors like trying to connect to a nonexistent slot are caught at compile time. The first is easily accomplished by giving the root class some sort of dispatch table (which is probably what the moc-generated code does anyway). The second is trickier, but using templates to leverage strong type checking would probably work.

All I'm really going on here is that the moc translates to vanilla C++, so it can't make classes do anything that normal classes can't do. All it does is give you more error checking than can be found in the C (or old C++) precompiler. With C++ templates, we have an extremely flexible, robust, and standard way of performing complex tasks at compile time.

I think if Qt were invented today, it would use C++ templates, and the moc would be unnecessary. If you think about the code that is actually generated,

connect( pbFoo, SIGNAL(clicked()), this, SLOT(fooClicked()) );

probably works a whole lot like

pbFoo->connect<SIGNAL(clicked())>(this, SLOT(fooClicked()) );

(feel free to swap pbFoo and this).

The added benefits would include increased flexibility, reduced "complicatedness," and an easier learning curve for C++ programmers.

Maybe someone should give this a stab.

Semi-editorial postscript: Thank you for putting the "about the author" paragraph in there. It's nice to have some context, and I wish more authors did this.

In this, as in all else,—
Y'r obd't s'v't.
tps12.—

Boost.Signals (5.00 / 2) (#20)
by e8johan on Wed Mar 19, 2003 at 09:31:49 AM EST

I would recommend you to look at http://www.boost.org/libs/signals/doc/index.html which I point out as an alternative in the text.

[ Parent ]
wow, cool (none / 0) (#22)
by tps12 on Wed Mar 19, 2003 at 09:45:26 AM EST

I forgot about that link. Those Boost dudes are so clever.

[ Parent ]
Boost (none / 0) (#48)
by Brandybuck on Mon Mar 31, 2003 at 05:40:59 PM EST

Now go try writing some stuff with Boost::Signals. Good luck. It feels almost like an academic excercise. It looks good, but doesn't work well in real life.

For example, say you want to have a functor or member function be the "slot". Now what happens when that object is deleted and you emit a signal? Go try it and see what happens. It's not pretty.

Now go check the size of an application that uses Boost::Signals versus the same application written for Qt. In one instance, which I did for a recent report, the Boost version was 30k while the Qt version was 16k. This wasn't because of templates, because I used used my own template signal/slot mechanism as a comparison, and it ended up being 15k.

[ Parent ]

TrollTech today (5.00 / 1) (#21)
by e8johan on Wed Mar 19, 2003 at 09:44:13 AM EST

http://doc.trolltech.com/3.1/templates.html deals with "I think if Qt were invented today, it would use C++ templates, and the moc would be unnecessary".

[ Parent ]
oops (none / 0) (#27)
by tps12 on Wed Mar 19, 2003 at 11:41:08 AM EST

Apparently I am not the first genius to think about this. Thanks for the links, Mr. Ohan.

Summary of a few essays, rants, and flamewars: The moc's shortcomings are evidently well-known and oft-discussed, but it's unlikely to be abandoned. "Ports" to Boost or libsigc++ will probably not be attempted (by Trolltech) given the support for templates in compilers available on Qt's target platforms.

Some people claim that signal management is not the only thing moc simplifies, and that a non-precompiled alternative would not be able to provide necessary Qt features, such as introspection. This tends to get a little hand-wavey, though, and I'm inclined to discount it.

From what I can gather, the moc persists because of the unfortunate state of template support in many compilers and plain old inertia.

[ Parent ]

That would be "complexity" [n/t] (none / 0) (#39)
by c4miles on Thu Mar 20, 2003 at 07:02:13 AM EST


--
For the Snark was a Boojum, you see.
[ Parent ]
Flexibility? (none / 0) (#50)
by Brandybuck on Tue May 20, 2003 at 02:54:27 PM EST

The added benefits would include increased flexibility

The flexibility would be reduced. I recently did a research for a class comparing Qt signal/slots to boost.signals. Template based signal/slots are very inflexible, despite their C++ "purity". Do your own investigation with a real application that uses both methods and you'll see. For simple static linkage between objects there's not much difference. But when you run into runtime polymorphism, "dangling callbacks", or otherwise managing the signals and slots at runtime, you'll appreciate the Qt's way.

[ Parent ]

YABOO. (3.00 / 4) (#23)
by porkchop_d_clown on Wed Mar 19, 2003 at 09:46:20 AM EST

"Yet Another Bag of Objects"

Seriously; the fact that there are so many different object collections out there is just more evidence that C++ doesn't quite cut it as an object oriented language. Rogue Wave, the good ol' NIH libraries, Qt and so on.

We don't need new libraries, we need a better language. Objective C, anyone?


--
You can lead a horse to water, but you can't make him go off the high dive.


Qt *is* the new language! (perhaps) (5.00 / 1) (#24)
by e8johan on Wed Mar 19, 2003 at 10:00:16 AM EST

I care to disagree. As Qt introduces signals and slots it also _extends_ the C++ model. These extensions make Qt-enhanced C++ a language which is more suitable for reuse and development of generic components. Through these extensions the need of a new language is even further away.

[ Parent ]

Huh? (4.50 / 2) (#25)
by gbd on Wed Mar 19, 2003 at 10:28:18 AM EST

Seriously; the fact that there are so many different object collections out there is just more evidence that C++ doesn't quite cut it as an object oriented language.

What in the world does toolkit availability have to do with whether or not C++ "cuts it" as an object-oriented language? I would tend to take the existence of multiple high-quality application development toolkits as evidence that C++ works rather well as an OO language (if it were so terrible, we wouldn't have any toolkits.)

--
Gunter glieben glauchen globen.
[ Parent ]

Then what about Java? (none / 0) (#30)
by Argel on Wed Mar 19, 2003 at 01:28:46 PM EST

The fact that there are so many different object collections out there is just more evidence that C++ doesn't quite cut it as an object oriented language

Then by your definition Java must be the worst OO language out there!?!



[ Parent ]
C++ is for writing objects (4.00 / 1) (#34)
by blackpaw on Wed Mar 19, 2003 at 08:01:27 PM EST

Seriously; the fact that there are so many different object collections out there is just more evidence that C++ doesn't quite cut it as an object oriented language

Huh ? This is evidence that C++ is a great object orientated language - its doesn't *supply* objects, it allows you to write them - hence the large amount of object libraries available for it.

[ Parent ]

Qt rules... (4.75 / 4) (#32)
by DJBongHit on Wed Mar 19, 2003 at 04:01:34 PM EST

... if you're trying to write a GUI-based program in C++, which is quite a common task these days. I used to write Qt-based software professionally, and I've experimented with many different C and C++-based toolkits. They range from GTK+ (the most god-awful API ever invented) to Qt (the cleanest, most beautiful C++ API I've ever seen). moc is a good thing - it lets more things than normal happen at compile time, with all the added benefits like type checking (templates would be another way to accomplish a lot of the same things, but compiler support still blows goats). I wrote a ton of Qt-based code, and it all ended up very maintainable and easy on the eyes (as well as being a solid final product).

But then I started playing around with OS X, specifically the Cocoa API. For those that don't know, Cocoa is an extension of the old NeXT API (OpenStep), and it uses Objective C. And I noticed that Objective C with the NSObject heirarchy did what Qt was trying to do natively, with even more power. Without getting into the details, Objective C is entirely message based, and objects send messages to each other rather than call methods, and message binding happens at runtime (well, a lot of it happens at compile time, so there's no hashtable overhead or anything... it's very efficient).

Because this functionality is built directly into the language and the runtime environment, it can do some neat things - all the way down to at runtime overriding a method (message handler) in any class - including those of the OS itself. Don't like NSString's memory management? Override the methods, and all code using it will transparently start using the new version - even code that was compiled and linked to NSString long ago. Even if the program has been running since before your NSString memory management stuff was written! And feel free to add new methods to NSString if you so desire - want built in regex matching (actually, IIRC it already has this, but I've never used it, so I'm not sure). The possibilities are unlimited.

Also, Objective C is much nicer than C++ in other aspects as well. For example, in C++ it is impossible to write 2 functions with the same name and the same argument types, because the compiler and linker won't be able to figure out which is which at call time. However, in Objective C, the argument names are part of the function signature and specified at call time:

[someBitmap scaleX:320 scaleY:240];

The name of that message handler is SomeBitmapClass:scaleX:scaleY (IIRC, it's been awhile, I've been in C++ mode for the last few months... objective C, while sweet, has no place in a game engine).

So, my verdict is that Qt is damn good if you're stuck with C++ or need it to be cross platform, but when writing a native OS X program, use the real thing. You won't regret it. And by the same token, in other situations you won't regret using Qt either. They're both good, but when you can use Cocoa, do so.

Also, if anybody knows any of the GNUStep developers, do me a favor and bitchslap them and tell them to get their asses in gear. The world needs a finished open source OpenStep implementation.

~DJBongHit

--
GNU GPL: Free as in herpes.

Game Engines (5.00 / 1) (#36)
by e8johan on Thu Mar 20, 2003 at 01:18:37 AM EST

Concerning "objective C, while sweet, has no place in a game engine", have a look at http://www.linuxjournal.com/article.php?sid=6009.

[ Parent ]
Close but... (none / 0) (#38)
by mahoney on Thu Mar 20, 2003 at 04:52:54 AM EST

Also, Objective C is much nicer than C++ in other aspects as well. For example, in C++ it is impossible to write 2 functions with the same name and the same argument types, because the compiler and linker won't be able to figure out which is which at call time. However, in Objective C, the argument names are part of the function signature and specified at call time:

This is wrong. In C++ you can't have methods with the same name and the same parameter types which is less restrictive than Objective-C. I think you have misunderstood the way Objective-C encodes method names. Let me give you an example.

- (void) someMethod: (int) anInt: (id) anObject;
- (void) someMethod: (int) anInt WithObject: (id) anObject;

These two methods take the same parameters but their name isn't the same. How would this be expressed in C++? By the following.

void someMethod(int anInt, id anObject);
void someMethodWithObject(int anInt, id anObject);

See? This possible to do in C++ as well. But in C++ if I wanted to do this,

void someMethod(int anInt, id anObject);
void someMethod(int anInt, Class aClass);

It would be valid but the following Objective-C code would create a name collision.

- (void) someMethod: (int) anInt: (id) anObject;
- (void) someMethod: (int) anInt: (Class) aClass;

Since the name of someMethod will be the same thing in both cases.

I don't disagree with your conclusion that Objective-C is a kick ass language, it is. In some areas it better than C++ in other areas it isn't. Mostly because the language hasn't been updated in a very long time. I hope things like exceptions, parameter type "overloading" on methods and some other things that I can't remember now will be added soon, to bring Objective-C up to date.

-- mahoney

[ Parent ]

GTK+ bashing (5.00 / 2) (#40)
by drquick on Thu Mar 20, 2003 at 11:05:32 AM EST

It's not surprising that Qt fans bash on GTK. Most of them know GTK from its 1.x days. The difference to 2.x is huge. http://gtk.org/api/ might give that insight.

You must understand that Gnome is more than GTK. Look at GObject, Pango, ATK. GTK is just one component of GTK+ and Gnome. Font handling and i18n is hidden from application software. Support for access enchancements in ATK is exellent. Gnome file ...um, data access model is implemented in gnome-vfs, It handles databases, files, multimedia (video, sound...), standard protocols (IMAP, HTTP, FTP etc,....)

Gnome/GTK+ is a fully object oriented API (unlike the GTK/Gnome 1.x days really...) but GTK is just a widget set. The core idea in GTK+ 2.x is the addition of GObject.

[ Parent ]

GTK+ 2 (none / 0) (#44)
by DJBongHit on Sun Mar 23, 2003 at 07:04:40 AM EST

It's not surprising that Qt fans bash on GTK. Most of them know GTK from its 1.x days. The difference to 2.x is huge.

You may be right, but I'm not going to look at the API behind it until the fucking thing actually works properly. GTK2-based programs are consistently the most problematic I encounter, and at least on my FreeBSD 5.0-RELEASE system, GTK2 is the only toolkit which STILL does not antialias text (well, out of GTK1, GTK2, and Qt, which are the only ones I expect such functionality from). GTK1 only does it by LD_PRELOAD'ing libgdkxft.so (Qt, on the other hand, has done it natively, not to mention flawlessly, for what, a year now?).

Once they get the userland wrinkles worked out, then maybe I'll ventune into the API again. Until then, I've got better ways to waste my time.

~DJBongHit

--
GNU GPL: Free as in herpes.

[ Parent ]
Gtk bashing (none / 0) (#45)
by bluebird on Sun Mar 23, 2003 at 07:12:24 AM EST

Still 95% of the applications written in Gtk are written with Gtk 1. So the bashing based on Gtk 1 is still justified. Even the core applications of Gnome take a long time to get ported to Gtk 2. Gtk 1 is going to stay for a lot more than everybody wishes. And Gtk 1 is awful, you need more than 50 lines of struct and macro hacks to declare an object.

Gtk 2 probably improves the situation. You can now have multiple inheritance and other stuff with GObject. But what's the point of it really ? Why implement a complete object system and then pretend you program in C ? If you want to use objects, inheritance and other fancy stuff, use them in your language. Do not rely on struct and macro and type-unsafe constructs for your programming. C++ and objective C have that. The compiler will do a better job at understanding your code if it knows that it is dealing with objects.

Gnome/Gtk is developed in C is just a joke. Gtk/Glib is as much C as Qt is C++. Some important Gnome applications are also develloped in C++ (GnomeMeeting).

And the main drawback of Gtk signal/slot system is still there in Gtk 2. Their signal can only carry static data, i.e. data declared per signal and not per object, so every slot ends up fetching the pointer to the signal emitter. See my other post for more explanation.

I just checked the tutorial to be sure:

gulong g_signal_connect( gpointer      *object,
                        const gchar   *name,
                         GCallback     func,
                         gpointer      func_data );

where [...] the fourth argument is the data you wish to have passed to this function.

By passing static data, Gtk has not evolved much from the event based toolkits. What a pity!

[ Parent ]

Object Oriented is not a language (none / 0) (#46)
by drquick on Sun Mar 23, 2003 at 10:45:38 AM EST

"Why implement a complete object system and then pretend you program in C ? If you want to use objects, inheritance and other fancy stuff, use them in your language."
Gnome is language independent. Anyhow it is a gross misunderstanding of OO to say that is something that's implemented in a language. OO is really a design methodoligy, that's its origins and its core. Writeing something in C++ does not imply it's an OO design. If you want to use Gnome objects in C++ - you can, and sure it helps in making the application you progam better OO. It helps a lot, of course, but thats an applications issue. The API is what counts, not the implemnentation language. You say GTK relies on macros, not really - if so, so does C++. C++ relies on C++ libraries. What I don't like about KDE is that it forces you to do your stuff in C++.

As for the point about signals, that's interesting to hear. I should check the roadmap to Gnome 3.0. It's been set long time ago. As for now there would be more flexible ways to transfer data.

[ Parent ]

OO in Logo (none / 0) (#47)
by bluebird on Sun Mar 23, 2003 at 11:40:34 AM EST

Sure, you can do OO programming in ASM, C, Logo, Pascal, Caml, Basic, Lisp, Bash, Awk or whatever language has not been designed for it. But it will be a lot more hassle.

It is a lot easier of you do OO programming in python, C++, Ojective C, Java, ...

The language is a key support for expressing your design. It is very painful when the language does not provide you with the freedom you need to express yourself. For example, you can not express the concept of virtual inherintance with Gtk 1.x and C. Your design will suffer from it or you will take the double of the time you normally need to recreate the concept virtual inheritance.

The tool has an influence on your creation. And OO is especially important in GUI application, where you basically stack plenty of objects that have to communicate together.

A bad language support will make the application more difficult to program. In the few times where I had to port a Gtk program to Qt (http://phil.freehackers.org/kde/cmp-toolkits.html), the Qt code was always at least 20% shorter. This is due directly to the language issue.

[ Parent ]

Signals and slots and shooting at your head (4.00 / 1) (#33)
by smallstepforman on Wed Mar 19, 2003 at 04:46:29 PM EST

You know, almost all other API's revert to good old fashioned Messages for inter process communication. Qt had to invent Signals and Slots to allow widgets to communicate with their appropriate methods. Now the million dollar question is - why? Whats wrong with using messaging when almost all platforms (Win32, Cocoa, BeAPI, Amiga etc) implement a very decent messaging system. Mind you, I'm unfamiliar with Qt's roots, but if it originated on X11, then I'm assuming that it had to work around the fact that the prefered method of IPC on X11 is via sockets, hence the need for signals and slots.

Wrong (X11 inter-application communication) (none / 0) (#41)
by CtrlBR on Thu Mar 20, 2003 at 05:11:20 PM EST

The preferred method of IPC on X11 is certainly not socket. Process using X11 displays may only have that display in common, so a proper X application can only use the display to communicate with its fellow applications sharing the same display. One way is to use Atoms if I remind well, it's very crude making that few application ever collaborate (or the choose not to be pure X11 based applications). I think that Motif drag and drop (see ICCCM) is based on this mechanism still.

My memory is quite fuzzy since it has been years I haven't done XLib programming but you see the point...

Any X11 programmer care to enlighten us?

If no-one thinks you're a freedom fighter than you're probably not a terrorist.
-- Gully Foyle

[ Parent ]
Messages (none / 0) (#51)
by Brandybuck on Tue May 20, 2003 at 03:01:31 PM EST

You know, almost all other API's revert to good old fashioned Messages for inter process communication. Qt had to invent Signals and Slots to allow widgets to communicate with their appropriate methods.

But Qt signal/slots are for intra process messaging. Why use X or win32 as the mediator between two objects in the same process?

[ Parent ]

Loose coupling (5.00 / 2) (#43)
by bluebird on Sun Mar 23, 2003 at 06:56:06 AM EST

While interesting, I think the article misses the most interesting advantages of signal/slots. This advantage is loose coupling between objects that communicate.

By loose coupling, I mean that the object that has a slot and the object that emits a signal don't have to know eachother at all. This allow to reuse a lot more objects than in other languages/toolkit I know.

In the example presented, in the first case, the problem is that you have to create a special FooButton class that needs to know that his parents is a dialog, just to get the functionality. In the second example, the author uses stock buttons.

In the first case, the connection between the button and the dialog has to be made through the language. In the second case, the signal/slots takes care of it.

It may sound trivial, but when an application grows, it gets many classes that need to communicate with eachother. System tends to get so complicated that there is a book describing how to organise all these objects : Design Patterns.

With the signal/slot system, many of the patterns described in design patterns are unnecessary. You can get rid of a lot of adapters, bridges and observers.

Let's take another example. Imagine I have a widget able to display a number (QLCDNumber to name it). This widget has a slot that accepts a number and displays it.

I can use a scrollbar that emits a value to control the display. But if I realise the scrollbar is not good, I can change to a dialer widget. It emits an int too so there is no change required to the receiver. Then I realise I have in fact only three choices, so three radio buttons will do it better. Still, the radio button group emits number, so that's no problem. After improving my application, I replace my radio buttons with some long background calculation, that emits a value at the end. Still I have no change to make to the receiver because for all this, I use signal with an int as the communication medium.

I can also change the receiver widget. If I realise a LCD display is not appropriate, I can replace it with a dialer that received a number. None of the emitter I have used will notice the difference, they will keep emitting their signal.

This is the power of loose coupling. With other toolkits, either the emitter class or the receiver class has to know about the other and sometimes both of them has to know eachother. This makes the communication more complex and less versatile. This is especially for event-based toolkits (MFC, wxWindow) where the information carried in the communication is minimal: an event means something has happened, the receiver of the event has to fetch the information by himself, so he ends up fetching objects (string coupling).

Java/Swing uses uses an adapter class to do what signal/slots do. While working, the solution is very heavy (one class per connection) and still not as versatile as Qt.

Gtk signal/slot come close but does not work because gtk signals carry only static data, and it is not straight forward to declare new signals or slots. The consequence is that their signal do not carry enough information. All the gtk programs I have witnessed actually fetch the pointer to the emitter in their slot and cast it to the object that has emitted the signal (to fetch the information they need). So the loose coupling is not there, the receiver has to know about the emitter.

The other template-based solutions (boost, libsig++) are interesting but they have two drawbacks: using templates in C++ is difficult and requires an advanced knowledge of C++ (less than 1% of C++ programmers acutally understand templates). Qt only requires to understand the concept of C with object to work with. The other drawback, which is also an advantage is that everything is tied at compile time by the templates. It is more difficult to import dynamically a plugin and connect to its signal/slots then within Qt where the signal/slot connections are internally ascii based.

More Qt | 51 comments (32 topical, 19 editorial, 0 hidden)
Display: Sort:

kuro5hin.org

[XML]
All trademarks and copyrights on this page are owned by their respective companies. The Rest 2000 - Present Kuro5hin.org Inc.
See our legalese page for copyright policies. Please also read our Privacy Policy.
Kuro5hin.org is powered by Free Software, including Apache, Perl, and Linux, The Scoop Engine that runs this site is freely available, under the terms of the GPL.
Need some help? Email help@kuro5hin.org.
My heart's the long stairs.

Powered by Scoop create account | help/FAQ | mission | links | search | IRC | YOU choose the stories!