Re: Steps to get to GTK+ 3.0



On Thu, 05 Jun 2008 00:37:00 -0400
Behdad Esfahbod <behdad behdad org> wrote:

> On Wed, 2008-06-04 at 07:35 -0400, Paul Davis wrote:
> > > Basically, something like this:
> > > 
> > >       http://doc.trolltech.com/4.4/properties.html
> > > 
> > > When reading this and other Qt documents, one realizes that a large
> > > technological gap separates GLib/GTK+ and Qt.
> > 
> > I don't want to start a flame war over old hat, but statements like this
> > shouldn't go unchallenged. GLib/GTK+ chose a different technology as a
> > base than Qt did (C vs. C++, and no pre-processing source versus
> > preprocessing source). As a result, some things that are easy in Qt are
> > hard in GTK+, but the reverse is true as well. If you want to see a
> > system that works more like Qt's (but better IMHO), you have only to
> > look to gtkmm.
> 
> We hear this again and again.  There are two statements here:
> 
>   * Qt is superior because it chose C++.
> 
>   * Qt does preprocessing.  GObject does not do preprocessing.
> 
> Both are wrong.  Specially the second one.  First, lets see what's on
> the table:
> 
>   http://doc.trolltech.com/4.4/metaobjects.html
> 
> Reading that page, say:
> 
>       *  QObject::metaObject() returns the associated meta-object for
>         the class.
>       * QMetaObject::className() returns the class name as a string at
>         run-time, without requiring native run-time type information
>         (RTTI) support through the C++ compiler.
>       * QObject::inherits() function returns whether an object is an
>         instance of a class that inherits a specified class within the
>         QObject inheritance tree.
>       * QObject::setProperty() and QObject::property() dynamically set
>         and get properties by name.
> 
> One can't help but notice that QObject is *exactly the same thing as
> GObject*.  With QMetaObject exactly being GObjectClass.  Means, even
> though Qt is based on C++, they had to reinvent the object system again,
> exactly the same way that GObject did, because C++'s object system is
> static.

Sure, both systems need some reflection capabilities, which neither C
nor C++ support natively. I don't see how this point would debunk the
fact that C++ is a more expressive language than C, and that writing
an object-oriented application in C++ is generally easier and more
pleasant than writing it in C.

I know that C++ has its share of issues, and I do understand why in
the nineties, the GLib people decided to use C and not C++. I actually
agree with their decision. Yet, if some people claim that "Qt is
superior because it chose C++", trying to disprove them with the above
argument is like trying to oppose general relativity with "because my
aunt Lilly likes to drink tea".

> Next, the preprocessing myth.  Source code using Qt is written into
> files with the .moc extension.  Then the .moc file is *copied intact*
> into a C++ file.  Let me repeat: no rewriting done.   And their custom
> symbols (signals, slots, Q_OBJECT, Q_PROPERTY) are simple macros.  Their
> moc compiler processes the moc source and creates another source file,
> containing the class metadata, and that's linked into the project.
>
> This is where it confuses people.  Qt could as well say "write proper C
> ++" and we just scan the .cc files straight.  Not sure why, perhaps to
> make build setup easier, they decided to call their dialect of C++
> moc.
>
> Now, people think GObject doesn't do the same.  We do.  Slightly
> differently.  In that:
> 
>   * We use plain .c for our GObject code.  No .go.
> 
>   * We don't use macros to add extra metadata to our classes or other
> types.  Guess what we use then?  Surprise! Comments indeed.  If you are
> not sure what I'm talking about, check glib-mkenums and
> glib-introspection.

Are you trying to suggest that Qt and GObject are on par with regard
to ease of use because GLib has tools for auto-generating enums,
marshalers and a few other things? Don't answer, see the code examples
at the end of this message.

I hope you'll pardon me the following paternalistic advice, but I
believe that it would be good for you to cut down on some of the
zealotry when defending a pet project. If you honestly acknowledge the
areas in which GLib is weaker, that will be put to your credit. But
continuing to claim that the earth is flat despite all evidence to the
contrary is rather unproductive.

> So, the "technological gap" mentioned in this thread, namely,
> 
> 	Q_PROPERTY(type name
>                     READ getFunction
>                     [WRITE setFunction]
>                     [RESET resetFunction]
>                     [DESIGNABLE bool]
>                     [SCRIPTABLE bool]
>                     [STORED bool]
>                     [USER bool])
> 
> Is not much technological (Q_PROPERTY expands to empty when compiling),
> as opposed to attitude.  GObject maintainers do not like changing the
> syntax of the native language (C), while Qt developers don't mind adding
> arbitrary syntax as long as it makes it feel more comfortable.

To the contrary, there is a significant technological difference. You
can use a bicycle to travel from city A to city B, or you can instead
use a jet-powered aircraft.

Likewise, you can implement a class "Foo" containing an int property
"bar" using the GObject way:

	#define G_TYPE_FOO		(g_foo_get_type())
	#define G_FOO(obj)		(G_TYPE_CHECK_INSTANCE_CAST((obj), G_TYPE_FOO, GFoo))
	#define G_FOO_CLASS(class)	(G_TYPE_CHECK_CLASS_CAST((class), G_TYPE_FOO, GFooClass))
	#define G_IS_FOO(obj)		(G_TYPE_CHECK_INSTANE_TYPE((obj), G_TYPE_FOO))
	#define G_IS_FOO_CLASS(class)	(G_TYPE_CHECK_CLASS_TYPE((class), G_TYPE_FOO))
	#define G_FOO_GET_CLASS(obj)	(G_TYPE_INSTANCE_GET_CLASS((obj), G_TYPE_FOO, GFooClass))

	typedef struct
	{
		GObject base;
	} GFoo;

	typedef struct
	{
		GObjectClass base;
	} GFooClass;

	GType g_foo_get_type (void);

	int g_foo_get_bar (GFoo *foo);
	void g_foo_set_bar (GFoo *foo, int value);

	enum {
		PROP_0,
		PROP_BAR
	};

	G_DEFINE_TYPE(GFoo, g_foo, G_TYPE_OBJECT)

	static void g_foo_get_property (GObject *object,
				        guint prop_id,
					GValue *value,
					GParamSpec *pspec)
	{
	  GFoo *foo = G_FOO(object);

	  switch (prop_id)
	    {
	    case PROP_BAR:
	      g_value_set_int(value, g_foo_get_bar(foo));
	      break;
	    default:
	      G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
	      break;
	    }
	}

	static void g_foo_set_property (GObject *object,
					guint prop_id,
					const GValue *value,
					GParamSpec *pspec)
	{
	  GFoo *foo = G_FOO(object);

	  switch (prop_id)
	    {
	    case PROP_BAR:
	      g_foo_set_bar(foo, g_value_get_int(value));
	      break;
	    default:
	      G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
	      break;
	    }
	}

	void g_foo_class_init (GFooClass *class)
	{
		GObjectClass *object_class = G_OBJECT_CLASS(foo);

		object_class->get_property = g_foo_get_property;
		object_class->set_property = g_foo_set_property;

		g_object_class_install_property(class,
						PROP_BAR,
						g_param_spec_int("bar",
								 NULL,
								 NULL,
								 0,
								 G_MAXINT,
								 0,
								 G_PARAM_READWRITE));
	}

	void g_foo_init (GFoo *foo)
	{
	}

	int g_foo_get_bar (GFoo *foo)
	{
		/* ... */
	}

	void g_foo_set_bar (GFoo *foo, int value)
	{
		/* ... */
	}

or using the Qt way:

	class QFoo : public QObject
	{
	   Q_OBJECT

	   Q_PROPERTY(int bar READ bar WRITE setBar)

	public:
	   void setBar (int value);
	   int bar () const;
	};

	void QFoo::setBar (int value)
	{
		// ...
	}

	int QFoo::bar ()
	{
		// ...
	}

Which way do you prefer?

-- 
Jean-Yves Lefort <jylefort brutele be>

Attachment: pgpAG6grRH6EG.pgp
Description: PGP signature



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]