Describe Vala/Ownership here.

This file is under changes, in construction.

Introduction

Vala introduces the ownership concept in programming. There is ownership in GLib, but it is ambiguous. This article will try to clearify the ownership concept in GLib and GTK, to clearify strong and weak reference, then to propose a definition for ownership in vala; finally I will check the conformity of vala 0.3.1 with the definition.

Definition of Ownership

Ownership

Consider an example before we begin. Imagine I have a bike; I use it everyday thus I don't borrow it to anyone.

How does the ownership by me work in the example? What privilege and obligation do I get by the ownership?

  • I can transfer the ownership to someone else.
  • I can dispose the bike any time I want.
  • Others can use the bike, but they can't dispose the bike; they can modify the bike if I am not modifying it (Locking mechnism in a multi thread environment)
  • Before I die, I have to either transfer the ownership, or to dispose the bike.
  • If someone really likes my bike, he can clone(copy) my bike by himself.

Think about another example. Imagine several people work in the same office. Consider the lights in the office.

  • When Tom enters the office, he turns on the lights, to produce the light;
  • Later when Sara enters the office, the light is already there and Sara enjoys it;
  • When anyone leaves the office, he/she has to check if nobody is in before he/she can turn off the lights.

Here, the relation between the officemats and the light is another kind of ownership. To be exact it is the strong reference. The difference between the bike and the light is that the bike is a non-reference-counted entity, whereas the light as a reference-counted entity.

strong reference is an extenstion to the simple ownership. If we ensure at the same time there is only one strong reference to an entity, strong reference falls back to ownership. However there is no way to promote simple ownership to strong reference.

Owner

In a simple ownership, the owner is the person who (will) dispose the entity; in a strong reference context, there are multiple owners, each has the possibility to dispose the entity.

A special case is that a code-block can and shall also be eligible to be an owner. Why?

The answer is simple: Because local variables are created and disposed during the life-time of the code-block. According to the ownership rule, they belong to the code block.

This simple fact is quite important, as it is the fundamental theorem to make possible automatic management in vala.

Ownee

Anything can(or shall) be disposed, shall be owned. Let's call it a ownee when it belongs to someone else. Obviously a GObject object is an ownee.

The non-referable entities, e.g, string(gchar *), boxed structs, are also ownees, because they shall be disposed. They should receive the same treatment as referable objects for the ownership.

A special case is GObject objects rooted from GInitiallyUnowned. They are created with no ownership. In GLib documents, it is said that language bindings where references are automatically handled should ignore the existance of GInitiallyUnowned. My understanding to this is that Languages has to explicity sink the floating reference of any GInitiallyUnowned objects to the code block.

Note: The current problem of Vala is that, Vala tries to keep track a 'reference count' of the non-referable entity 'string'. This assumes string are immutable, which is annoying. However, reference count has nothing to do with the ownership, and we can safely remove the immutability assumption, treating string in the same way as other non-referable entities.

Ownership in GLib

This section is to demostrate, (thus to support) my argument that GLib utilities Ownership without directly using it.

There are three typical code-segment can be explained in the ownership language in GLib and GTK.

In this section the code are *NOT* vala code, they are pseduo GLib code.

Transferring Ownership

char * key = strdup("key");
GObject * obj = g_object_new(...);
GHashTable * hash = g_hash_table_new(...,...,g_free, g_object_unref);

g_hash_table_insert(hash, key, obj);

/*no g_free(key) since the ownership is transferred.*/
/*no g_object_unref since the ownership is transferred */

The hashtable will own the object and the key.

When you remove them by

g_hash_table_remove(hash, key)

They will be disposed by the hashtable, and that's why the hash table own the object .

When you lookup them

GObject * o = g_hash_table_lookup(hash, key);

You get a weak reference of the obj, then you can turn it into strong. But when you steal it

GObject * o = g_hash_table_steal(key);

you get the ownership of the o, and also the keyword when you create the hash. However, although the ownership of the keyword is obtained, there is no availible weak reference(pointer), thus no way to dispose it. I'd rather call this 'the expense of stealing'.

Establishing Ownership

I'll use GtkWidget as an example. GtkWidget is based on GInitiallyUnowned. In the C binding, the code block that creates the object doesn't own the object.

  {/*code block A*/
   GObject * object = gtk_widget_new(....);
   GtkContainer c = gtk_container_new(...);

   GtkContainer.add(object);
  }

code block A doesn't have the ownership of the object. The object's ownership is, then established with the container.

In Vala, (as vala is a reference-caring language), we should, (1) always sink the floated reference as the object is created, or (2) show the awareness of the floating reference, e.g., invent some grammar to reflect this.

Collection without Ownership

GList, GQueue and GSList are three simple collections. In GLib, they have completely no ownership management. To mention again, it is because they are not awaring the disposal of the children.

The ownership management is then fall back to the owner of the collection. Here is a piece of code implementing the management:

GObject * obj = g_object_new(..);
GList * list = NULL;
list = g_list_insert(list, obj, -1);
/*no g_object_unref because it is transferred*/

To remove the object:

list = g_list_remove(list, obj);
/*GEE, the reference count is leaked, we have to explicitly*/
g_object_unref(obj);

To dispose the list

/*GEE the references of children are leaked, we have to explicitly dispose them*/
for(GList l = list; l; l = g_list_next(l)) g_object_unref(l.data);
g_list_free(list);

Vala is trying to handle this issue by implicitly automatically embedding the ownership management code. I don't quite like the solution, because in the generated C Code, the true owner of the collection's children becomes a dim figure. Anyway Vala should, support the native GList via <weak> generics.

Ownership in Vala

This section is not how vala 0.3.1 works: it is only a proposal for how vala should work.

Referable and Un-referable Entities

Referable entities are entities that has a .ref() and .unref() member. Referable entities are disposed when all the strong references added by .ref() are removed by .unref() method.

Un-referable entities are the opposite. There are no .ref() and .unref() member for them. string (char *) and types not inherited from Object are of this type. As there is no reference counting mechanism, there is no strong reference to ensure the life time of these entities. On the other hand, weak is the only meaning full reference for them.

Strong and Weak Reference

I was confused with ownership and strong reference. I guess it also either confused or is confusing others. Thus this section is to clearify them.

Let's go back to the (not so appropriate) bike example. A strong reference to the bike is someone borrows the bike and have a seat on it. A weak reference to the bike is some borrows the bike and, only look at it(and also get notified when I dispose the bike).

Because a weak reference is only looking at the object, it doesn't affect the disposal process when I don't want the bike or I die. On the other hand, a strong reference affects the disposal process in the ownership, because a strong reference holds a reference count.

It is thus no good to strongly refer to a non-referable entity. There is no way to track the reference from the owner.

Whether intended or not, Vala tries to keep track (simulate) of string references, by consuming the memory with propagating strings. It is even more like a virus by assuming the strings to be, identical, immutable copies.

Strong Reference

A Strong Reference is an entity. It refers to a referable entity that supports reference counting. When the strong reference entity goes beyond its scope, the strong reference entity is destroyed, and the reference it holds is released.

If there is a need to declare a strong reference explictly, I would like to use

strong Object o; 
@ GObject * o;

to define an uninitialized strong reference of an Object object.

The first assignment to the reference is to initialize the reference:

o = new Object();
@ o = g_object_new(G_TYPE_OBJECT, NULL);

No g_objec_ref here. The object already has a reference count of 1 after g_object_new.

For InitiallyUnowned, it has to be different. Vala has to track the inheritance tree of the GType system at compiling time to ensure this:

o = new InitiallyUnowned();
@ o = g_object_ref_sink(g_object_new(G_TYPE_INITIALLY_UNOWNED)); /*sinking the unowned object since it is strong!*/

Another method to deal with the InitiallyUnowned, is to add a modifier floating:

floating Object o = new InitiallyUnowned();
@ o = g_object_new(G_TYPE_INITIALLY_UNOWNED);

Now lets put the stuff together

class MyObject:Object{
   strong Object o;
   public void myfunction(Object obj){
      o = obj;
   }
   static void main(string[] argv){
      strong Object o = new Object();
      strong Object myobj = new MyObject();
      myobj.myfunction(o);
   }
}

Notice that there is no strong modifier in the decleration of myfunction. Because a formal parameter shall only specify the type of the object(and as later I will indicate, the transferring of the ownership. The less it says, the more exact it represents.

The corresponding C code shall be

void my_object_myfunction(MyObject * this, GObject * obj){
   this->priv->o && g_object_unref(this->priv->o);
   this->priv->o = g_object_ref(o);
}
void my_object_dispose(MyObject * this){
   this->priv->o && g_object_unref(this->priv->o);
}
void main(int argc,char * argv[]){
   GObject * o = g_object_new(G_TYPE_OBJECT, NULL);
   MyObject * myobj = g_object_new(TYPE_MY_OBJECT, NULL);
   myobj.myfunction(o);
   g_object_unref(myobj);
   g_object_unref(o);
}

Either 'strong' and 'float' can always be inferred from the context, and thus, can be always omitted. However, programmers shall have these concepts in mind. Vala can hide these details but vala shall also let its programmers know what is happening behind the sense. Vala shall not aim to be another C#. Vala shall aim to be the productive language of GLib programming.

Weak Reference

A Weak reference is an entity, that, refers to another entity without holding any reference count. Weak reference is, loosely speaking, a pointer without the asternoid.

In other words, it is an unprotected, unmanaged, unsafe pointers to the object, but it looks exact like a reference. Also, a weak reference means a notification mechanism when the entity it refers to is disposed. ( However, in Vala, this important concept is lost )

In Vala tutorial, weak reference is not very recommended. Nevertheless, as a general rule, bad things are always as useful as their badness if one can use it in a good way.

Their importance will show up when we later talk about the ownership management. They are the best partner of Ownership. As I have pointed out at the very beginning, the rule 3 of ownership breaks ownership by denying the owner to dispose the ownee immediately. An object in that state is actually floating with many strong reference plugged in, and vulnerable to other strong referees.

Weak reference, however, doesn't break rule 3. As in a carefully designed program the occurance of rule 3 shall be suppressed and controlled, almost every strong reference can be replaced by weak reference.

If one examines the GTK code, it also seems that most references are weak. It is the widely use of weak reference in GLib that makes it so elegant: The programmer always understands what he/she writes or the code crashes, thus efficient code is written.

weak Type o; 

Defines an uninitialized weak reference of an Type entity.

It doesn't make sense to initialize a weak reference with an new Object(); it only makes sense to initialize a weak reference with a new InitiallyUnowned(). Thus

weak Object o = new Object(); //is wrong.

Vala compiler checks for this and panics.

However for an InitiallyUnowned it shall be valid:

weak InitiallyUnowned o = new InitiallyUnowned(); // is OK.
@ GInitiallyUnowned * o = g_object_new(G_TYPE_INITIALLY_UNOWNED);

Take an example:

class MyObject:Object{
   weak Object o;
   public void myfunction(Object obj){
      o = obj;
   }
   static void main(string[] argv){
      strong Object o = new Object();
      strong Object myobj = new MyObject();
      myobj.myfunction(o);
   }
}

It will be translated into

void my_object_myfunction(MyObject * this, GObject * obj){
   this->priv->o = o;
}
void my_object_dispose(MyObject * this){

}
void main(int argc,char * argv[]){
   GObject * o = g_object_new(G_TYPE_OBJECT, NULL);
   MyObject * myobj = g_object_new(TYPE_MY_OBJECT, NULL);
   myobj.myfunction(o);
   g_object_unref(myobj);
   g_object_unref(o);
}

Casting Strong to Weak

It is always possible to cast a strong reference to a weak reference, in which situation a new weak reference entity is created, referring to the entity referred by the strong reference.

Ownership

The essential of ownership is the obligation to dispose.

For referable entities, a strong reference will work as an ownership reference. Let's examine how it conforms with the 4 rules of ownership in Vala:

  1. If the new owner add a ref to the ownee, and the old owner release a ref, the ownership is transferred.
  2. If no others hold a strong reference to the ownee, and the owner releases the reference, the object is disposed immediately.
  3. If others holds strong references to the ownee, and the owner releases the reference, the ownee becomes vulnerable and is disposed when other references are released.
  4. When the owner dies, the reference it holds is automatically removed by the vala compiler, if the ownership is not transferred.

For non-referable entities, ownership can not be a strong reference, since there is no strong reference. A ownership reference is simply a weak reference plus a tag to notify the compiler to destroy the entity when the owner passes out; the tag can be transferred too.

Thus the ownership modifier can also always safely be omitted, given that the compiler can always either fall to the strong reference, or infer to use the ownership reference. However, the programmer, shall keep it in mind which is the ownership reference and which is not. Vala shall also check at compiling time for that the ownership transfer is valid, which is implemented and passed to the run-time code. (by setting transferred object reference to null).

class MyObject:Object{
   ownership Object o;
   ownership string s;
   public void myfunction(Object # obj){
      o = obj;
      s = new string("my little string");
   }
   static void main(string[] argv){
      ownership Object o = new Object();
      ownership Object myobj = new MyObject();
      myobj.myfunction(#o);
   }
}

As the tradition in Vala, # is for ownership transferring. Also notice the decleration of myfunction, there is a # modifier to indicate, that, the method will take away the ownership of the caller. So that the compiler can take the corresponding action toward it.

It will be translated into

void my_object_myfunction(MyObject * this, GObject * obj){
   this->priv->o && g_object_ref(this->priv->o);
   this->priv->o = obj;
   this->priv->s && g_free(this->s);
   this->priv->s = g_strdup("my little string");
}
void my_object_dispose(MyObject * this){
   this->priv->o && g_object_ref(this->priv->o);
   this->priv->s && g_free(this->s);
}  We will go deeper into this issue when we finish constructing the Ownership.
void main(int argc,char * argv[]){
   GObject * o = g_object_new(G_TYPE_OBJECT, NULL);
   MyObject * myobj = g_object_new(TYPE_MY_OBJECT, NULL);
   myobj.myfunction(o);
   g_object_unref(myobj);
  /*the ownership of o is transferred, thus the caller doesn't dispose it.*/
}

The code is very much the same as the strong reference version, except less ref count is involved. Also, a string is properly dealt.

Improper Use of Ownership Transferring

A common improper use of transferring ownership in Vala, ( and no error is given at compile time) is to forget to put a # in the caller. The compiler is modified to work in an in-consistent way to generate non-leaking code for this case.

Confliction with Generics Programming

Consider a collection

class Collection<T> {
    public void insert ( T # obj);
}

If T is given a weak reference, it can not take the ownership. Hence T # in insert doesn't make any sense. Two ways to solve the confliction:

  • 1 Not allowing T to be weak, because, T is a type not a reference; Bad Idea because of not allowing weak reference for simulating pointers and to use the native GList semantics. 2 Treat weak reference itself as a type, and because a weak reference entity does not require to be disposed, its ownership can be transferred arbitarily.

The second way is more inspiring; If we extend the idea, a strong reference can also be a type, and then ownership of an entity of strong reference type can also be transferred. The rule to infer whether a strong reference is an ownership need to be more specific:

  • 1 If the reference is initialized with an Object, the refrence is an ownership. 2 If the reference occurred in a ownership transferring, it is an ownership.

For non-referable types, there is no such problem to distinguish 'ownership' and 'strong reference':

  • 1 If the reference is not weak, it is an ownership.

Conformity

feature

status

Handling Ownership in simple collections

no

Panic for weak reference for referable objects

yes

Weak reference for InitiallyUnowned

not tested yet

References as entities

state unknown

Casting strong to weak

yes

Casting strong to weak ownership transferring at formal parameter

yes

Implicit strong keyword

yes, but not purposely

Implicit ownership keyword

yes, but not purposely

Explicit strong keyword

no

Explicit ownership keyword

no

Strict ownership transferring grammar

no

Weak reference as entity type in generics

yes, but not purposely

Panic for strong reference as entity type in generics

N/A because no explicit strong keyword, they are inferred to be ownerships

If the compiler purposely implement 'strong' and 'ownership' we can produce more efficient C code. It will also allow us to write code to clearly demostrate how ownership and reference work in Vala.

Projects/Vala/Ownership (last edited 2013-11-22 16:48:29 by WilliamJonMcCann)