Re: GObject tutorial next version
- From: Tiago Cogumbreiro <cogumbreiro linus uac pt>
- To: Ryan McDougall <NQG24419 nifty com>
- Cc: Gtk+ Devel <gtk-devel-list gnome org>, Gtk+ <gtk-list gnome org>
- Subject: Re: GObject tutorial next version
- Date: Thu, 26 Aug 2004 11:13:34 +0000
My comments follow in a patch :) Nice tutorial.
On Thu, 2004-08-26 at 07:33, Ryan McDougall wrote:
> This covers everything except signals, which is the last thing to do.
>
> Warning currently its in plain text format since I haven't gotten around
> to fancifying it yet, however it WILL be prettied up.
>
> I'd appreciate feedback on technical, spelling, grammar, or style
> points.
>
> Cheers,
> Ryan
>
> ______________________________________________________________________
--- gobject-tutorial.txt.original 2004-08-26 11:11:51.300133832 +0000
+++ gobject-tutorial.txt 2004-08-26 11:10:12.985079992 +0000
@@ -22,7 +22,7 @@ In OO languages object oriented features
Design
-----
-In OO, an object consists of two types of members bound under one object reference: data fields and method functions. One way to accomplish this in C is with C structs, where data fields are regular public members and methods are implemented as function pointers. This implementation however has several serious flaws: awkward syntax, type-safety, and lack of encapsulation to name a few. However there is more practical problem -- it is a serious waste of space. Every instance object needs a 4-byte pointer for each of its methods; all of which will be identical class wide, and thus totally redundant. That is to say if we have a class with only four methods, and a program with 1000 instantiation objects of that class, we are wasting almost 16KB. Clearly we'd be better off memory-wise if we only kept one copy of those pointers in a table that could be accessed by any object in its class.
+In OO, an object consists of two types of members bound under one object reference: data fields and method functions. One way to accomplish this in C is with C structs, where data fields are regular public members and methods are implemented as function pointers. This implementation however has several serious flaws: awkward syntax, type-safety, and lack of encapsulation to name a few. However there is a more practical problem -- it is a serious waste of space. Every instance object needs a 4-byte pointer for each of its methods; all of which will be identical class wide, and thus totally redundant. That is to say if we have a class with only four methods, and a program with 1000 instantiation objects of that class, we are wasting almost 16KB. Clearly we'd be better off memory-wise if we only kept one copy of those pointers in a table that could be accessed by any object in its class.
Such as table is called a virtual method table (vtable), and one copy is kept in memory by the GObject system for each class. When you want to call a virtual method, you must ask the system to find the object's vtable; which as we have said above is just a struct with function pointers. With this you can now dereference the pointer and thus call the method.
@@ -43,6 +43,7 @@ Non-virtual methods will be implemented
<notice>
While OO normally uses information hiding as part of encapsulation, there is no easy way to hide private members in C. One method is to put your private members into a separate struct that is defined in the source file only, then place a pointer to the private class in your public object struct. However, in a open-source world this is small protection against a user determined to do the wrong thing. Most developers simply label with a comment those members they wish to protect as private, and hope the user respects the distinction.
</notice>
+*****Not a very correct notice, a user can use g_type_class_add_private, as in this example: http://s1x.homelinux.net/documents/gtk/gobject-faq.html#toc4
At this point we have two distinct structs, and no obvious way to find to get the proper vtable given an instantiated object. As we implied above, it is the system's responsibility to do so, and it is able to handle this only by requiring us to register the types we create. The system also requires us to register both (instance and class) structs' initialization and finalization functions (and some other important information), which will allow the system to properly instantiate our objects. The system keeps track of our objects by enumerating all types registered with it, and requiring that all instance objects start with a pointer to its own class vtable, and each vtable start with the number that corresponds to its enumerated type.
@@ -62,6 +63,10 @@ Create "C-style" objects using the struc
<notice>
We prepend an underscore to the name of our struct, then add a forward typedef which gives our struct a proper name. This is due to the grammar of C, which won't let you declare SomeObject pointers inside SomeObject (which is handy for such things as linked lists). We have also created an artificial namespace called "Some", as described by our convention above.
</notice>
+****** I know that this is a matter of style but the 'm_' prefix is usually
+used in OOP languages so that you can explicitly tell apart an instance
+variable from a normal variable, in GObject we already have the 'self->' prefix to tell that, therefore it seems
+a bit of overhead. Also, this type of convention is not used in Gtk+ sources.
/* Our "Instance struct" defines all the data fields that make our object unique. */
typedef struct _SomeObject SomeObject;
@@ -113,6 +118,10 @@ void some_object_method3 (SomeObject *se
Create some boiler-plate code which will make our code comply to existing standards and generally make our lives easier.
</step>
+************** where are namespaces? Also according to convention it should
+be: TYPE_SOME_OBJECT, IS_SOME_OBJECT, IS_SOME_OBJECT_CLASS, but if 'Some' is
+the namespace then it should be SOME_TYPE_OBJECT and the rest is correct.
+
/* Handy macros */
#define SOME_OBJECT_TYPE (some_object_get_type ())
#define SOME_OBJECT(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), SOME_OBJECT_TYPE, SomeObject))
@@ -257,6 +266,7 @@ GType some_object_get_type (void)
}
/* Lets build a simple test driver for out our code! */
+****************Why not use the macro instead of _get_type function?
int main()
{
@@ -509,6 +519,7 @@ struct _SomeObject
/* Some useful fields may follow. */
};
+********* Isn't GTypeClass supposed to be GObjectClass?
/* Our "Class struct" defines all the method functions that our objects will share. */
typedef struct _SomeObjectClass SomeObjectClass;
struct _SomeObjectClass
@@ -530,6 +541,10 @@ Code (source)
We need to add declarations for the GObject specific methods we are going to override.
</notice>
+*********** instead of using g_type_class_peek every time why not use a static
+and global variable instead? Especially if you use G_DEFINE_TYPE macros one
+will be created for you.
+
/* These are the GObject Construct/Destroy methods. Their signatures are determined in gobject.h. */
void some_object_constructor (GType this_type, guint n_properties, GObjectConstructParam *properties)
{
@@ -674,6 +689,7 @@ Code (source)
Create an enumeration for internally tracking properties.
</step>
+**************why the bit shifting?
enum
{
OBJECT_PROPERTY_A = 1 << 1;
@@ -725,6 +741,8 @@ void some_object_set_property (GObject *
Override the set/get_property methods inherited from our parent and install GParamSpecs.
</step>
+*********** you could've mentioned G_PARAM_READWRITE
+
/* Here is where we override any functions. */
void some_object_class_init (gpointer g_class, gpointer class_data)
{
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]