Re: [Vala] Chaining up constructors.



On Sun, 2008-11-23 at 00:13 -0500, Yu Feng wrote:
Hi Hans,

Thanks for the reply.

To avoid confusion, can we use CreationMethod and construct block to
refer the entities?

sure, no problem.

For class types I will use GObject classes and fundamental classes.
[...]
On Sun, 2008-11-23 at 02:47 +0100, Hans Vercammen wrote:
(1) You either use the classical GObject construction scheme with a
registered constructor function (the construct block) and GObject
(construct) properties as parameters. You need [CCode
(has_construct_function = false)] for your creation methods if you only
want use this.

(2) You use the new chaining constructor functions, which are the
default and not limited to the classical construction scheme
requirements. They do break the classical GObject construction outside
vala, so you probably need watch out with this when these objects are
only created with g_object_new somewhere. You can still use a construct
{} block. But these blocks are triggered and chained in the g_object_new
call, so they don't always make much sense when using custom chained
constructors.

Currently (1) doesn't work at least for chaining up constructors. After
chaining up, all logic in the child creation methods are lost. The ccode
contains some code to free GParameters.

Agreed, standard GObject subclassing doesn't allow custom constructor or
creation method chaining. You only have one constructor function that's
usable, the construct block. The creation method should only allow
property assignments in this case as it was prior to vala 4.0.

And I don't think the two GObject options are mutually exclusive. I
can(should be able to) do some logic in the creation method, set the
G_PARAM_CONSTRUCT properties, and then do some other initialization in
the construct block. 

They are not mutually exclusive, but if you choose to do custom logic in
the creation method, this logic is only executed when the class is final
and not when the object is constructed with g_object_new or subclassed
as in (1). Initializations in the construct block are always executed,
whether constructed with a creation method or eventually with
g_object_new. That's why you should carefully consider what to
initialize where and when.

For (2), I don't think if it is a real breakage to the GObject
semantics. It is not rare that in GTK, the creation methods (_new)
behaves completely different from g_object_new; and there should also be
examples where class creation methods and GObjectClass->constructor were
used simuntenaeously. 

Are you sure about this? I'm not familiar with the Gtk+ internals, but
it would be strange that the subclassing would follow a different
initialization path, compared to the creation method.


But then again, if you use the new scheme, you can freely switch your
base class to a fundamental class or a gobject one without having to
change anything. This also implies that I could do something like bellow
which is not possible with the classical GObject construction scheme:


Both vala 0.5.1 and trunk fails to smoothly switching the parent
classes. if I have extra stuff in the creation methods.

Yeah sorry, from what I understand construction chaining isn't fully
supported yet with fundamental classes.

I don't think you should mix the two construction schemes to much as
they are essentially incompatible. GObject basically doesn't support
custom constructor chaining interference, so if vala wants to support
this (and by doing so breaking the GObject way a bit), why keep the
property assignment limitation?

Why are they essentially incompatible? As far as I know the construct
blocks corresponds to Klass->constructor, and they are automatically
chained up.

Yes, they are automatically chained, but the time of execution is very
different and you have only one construct block to use for this.

If you mean chaining up the CreationMethods, I still can't see any
incompatibilities.

Recall what in general a creation method should do(not specifically
tided with GObject or Vala GType based Classes, or C++ or any
languages). A creation method takes parameters, do some logic, allocate
the memory for the object, and assign initial values for the properties.
right?

Sure, but if you look at it that way, you can't really chain the
creation methods into an object hierarchy.

Now let's investigate what we really mean by chaining up creation
methods. Obviously, memory allocation should not be chained up: the
parent class doesn't know the size of the child class. It is the logic
and initial value assignment that are chained up.

Good, now we can see two different sections in the creation methods.
Keep this in mind. Think about implementation now.

Suppose we want to chain up the the creation methods in GObject.
g_object_new, can do two jobs: memory allocation and value assignment.
Therefore, for chaining up, we have to call the base logic part of the
creation methods and collect the value assignments, then invoke
g_object_new with the collected value assignments to finish the
semantics of a creation methods.

I can follow your logic to enforce standard GObject construction using
properties, but I don't understand where you are going to execute your
custom creation method logic in this case.

Suppose we want to chain up the creation methods in fundamental classes.
We have a function g_type_instance_new, for the memory allocation.
Therefore, we can call the parent creation method's logic and the value
assignment part to do the chain up.

Yes we can now see at the implementation level, creation methods for
GObject are incompatible with those for GType based vala classes. But
vala compiler should be able to hide these details from the end users,
right?

Sorry, I've lost it a bit. Fundamental classes are not bound to the
GObject property construction mechanism, so chaining these creation
methods shouldn't be a problem at all. It's the GObject constructor
chaining that's the problem, which is also why (as I understand it)
there are two construction mechanisms for it.

As a consequence, I also consider it to be a great performance
enhancement not having to use GParameters and construct properties. The
GObject constructor function only takes construct properties, the others
are filtered out in the gobject core. So I think you would have to use
construct properties by default in this case, which again is very slow.

non G_PARAM_CONSTRUCT properties should not even be thought as
properties in a CreationMethod. G_PARAM_CONSTRUCT properties, to me
serves mainly for read-only properties initialized at the object
creation.

eg:

class A :Object{
   public int val {get; construct;}
   public int lav {get; set;}
   public A.with_val(int val) {
      this.val = val;
      this.lav = val;
   }
}

val should be initialized with g_object_new, where as the line
containing lav should be treated as the logic of the creation method,
and compiled as regular vala statements -- to a_set_lav(self, val);

Still, I think we are talking about different things here. The new
constructor chaining for GObject based classes allows you to do much
more than what is enforced by the standard GObject mechanisms. It's more
an additional initialization layer on top of the GObject construction
mechanism. You are no longer required to use properties for constructor
arguments, as vala provides you a custom construct (initialization)
function for this which can be easily chained up.

Hans




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