Re: [Vala] Chaining up constructors.



Hi Hans,

Thanks for the reply.

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

For class types I will use GObject classes and fundamental classes.

On Sun, 2008-11-23 at 02:47 +0100, Hans Vercammen wrote:
Hello Yu,

On Fri, 2008-11-21 at 21:27 -0500, Yu Feng wrote:
Dear Jurg and others,

I have an idea about chaining up constructors to share with you.

Situation
========
We have 2 different constructors, the construction block(CB), and the
construct function(CF).

for GType based classes, CB doesn't work, chaining up CF works.
for GObject based classes, CB works, chaining up CF doesn't.

We also have construct properties(CP); CF can and should initialize CPs,
CB can not and should not.

Whenever there is a CF, two CCode functions are generated: _construct
and _new. For CB, _constructor is generated.

The memory allocation is done in _construct.

New Idea
=======

The basic idea is to move memory allocation to _new functions, and let
_construct functions initialize the properties. It is then much easier
to chain up the _construct functions without worrying about memory
issues. The other idea is to manifestly invoke '_constructor' for GType
based classes. 

With these two changes, we can arrive the maxium symmetry between
GObject classes and GType classes. It also permits one to freely switch
the base type of any classes between GLib.Object and nothing without the
need of modifying any code.

I have to agree, I'm a bit confused with the current situation. As I
understand it, please correct me if I'm wrong; you now have two options
for GObject based construction.

(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.

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. 

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. 


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.

public class Foo: Object {
      private string data;
      public Foo (string data) {
              this.data = data;
              stdout.printf ("Foo::data %s\n", data);
      }
}

public class Bar: Foo {
        public string other {get;set;}
      public Bar () {
              base ("John Doe");
                this.other = "";
      }
}

public class Maman: Bar {
}

Of course, when this is not the intentional behaviour and my assumptions
are wrong, we should probably fix this as soon as possible! Because I'm
sure that a lot of people that are not familiar with GObject are going
to use it this way.



Yes. If the current approach can work, there is no need to invent a new
one. But after some investigation into the current implementation in the
trunk, I am not so confident that treating _construct and _new as a
virtual function pair is a good idea. We can go further than that.


For GObject based classes:
-----------------------
1. for each CF, generate a _new function,
Object _new(param1, param2, param3...) {
int n_params;
GParameter * params = _construct(&n_params, param1, ....);
return g_object_newv(TYPE, n_params, params);
}

2. for each CF, generate a _construct function,
GParameter * _construct(&n_params, param1, param2, param3) {
    translate all the logic in CF, if there is an assignment to a property
with getter and setter, create the correspoding GParameter
        chain up is also done here by merging the return value of the
parent's _construct function.
}

3. for each CB, generate the _constructor function, and hook it to the
GObject class structure.

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.

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?


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.

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?


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);

Thanks for reading all of these (might be nonsense to you) and,

Regards,

Yu
Regards,
Hans






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