Classes#

A class is the most common variant of types in Vala. It describes the way an object, or also called an instance of this class, should behave and look like.

How to instanciate a class#

Instanciation is the process of constructing a new object from a class. This is very simple:

// declare a new variable of the wanted type
Gtk.Window window;

// instanciate an object of that type
window = new Gtk.Window ();

The important part here is the new keyword. To find the right way to construct an object of specific type, look into the API references. Sometimes there are multiple ways to do this.

What features do classes have?#

In Vala classes have the most features a type can have.

Tip

Sometimes you don’t need all these features though and a more lightweight option like a compact class or struct is better.

  • Derivation

  • Interface implementation

  • Reference Counting

  • Private Fields

Additionally when you derive from the base type GLib.Object, you get also these features:

In most cases you are going to derive from GLib.Object.

How to create your own class#

This is very easy:

public class MyClass : Object {

}

Here you have created your own class named “MyClass”. In Vala types are usually in “CamelCase”.

After the : the class you derive from is specified. In this case Object. public is an access modifier, which defines, who can see this class. Here it is visible to just everyone.

Inside of the brackets now you can now put the data, that an object of this class should contain, and the code that works on those objects:

public class MyClass : Object {

    public MyClass () {
        Object ();
    }

    construct {
        // constructor
    }

    public int a_property { get; set; }

    public bool my_method () {
        // do stuff
    }

    private string a_field = "initial value";

    public signal void my_signal (float b);
}

You can read more about each of them in the other pages of this chapter.

Final classes#

You can make a class final with the sealed keyword:

public sealed class MyClass : Object {
    // ...
}

This makes it impossible to derive this class further.

Warning

Where ABI compatibility matters you should default to final classes. Later they can be turned into derivable ones without a break, but not the other way around.

If classes are derivable or not is part of the API design. There should be a reason why you can derive a class further. If not, then make it final.

Construction of a class#

The construction is the process of building a new instance by allocating memory for it and intialising it with the right values. There are multiple places where you can insert code to do that:

  • The construct block is the most common place:

    public class MyClass : Object {
    
        construct {
            stdout.printf ("%d instances were already created".printf (n_instances));
            MyClass.n_instances++;
        }
    
        private static int n_instances = 0;
    }
    

    The construct block is run after the construct properties have been set. So you can access them. Also other methods of the object can be called.

  • In the static construct block static class members are initialised with data. This happens only once. It is useful if you have resources that are the same for every instance and instances of subclasses:

    public class MyClass : Object {
    
        static construct {
            MyClass.some_numbers = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
        }
    
        private static int[10] some_numbers;
    }
    
  • For data that is the same in all instances of a class, but not subclasses of it, you can put it into class fields and intialise them in the class construct block. This is executed only whenever the first time the class is used.

    public class MyClass : Object {
    
        class construct {
            file = File.new_for_path ("my-file.txt");
        }
    
        private class File file;
    }
    
    public class AnotherClass : MyClass {
    
        class construct {
            file = File.new_for_path ("another-file.txt");
        }
    }
    

Tip

You will most commonly use static members instead of class members. Only in case a field should be overridable in subclasses with a custom value, or other dynamic object, you should use class members.

Custom Constructor#

Also usually you want to write your own custom constructors, to simplify constructing your class:

public class MyClass : Object {

    public MyClass (int a) {
        Object (a_property: a);
    }

    public int a_property { get; set; }

    construct {
        stdout.printf ("'a_property' was intialised with " + this.a_property.to_string ());
    }
}

You can do this by writing a method with the same name as your class (MyClass), but without a return value. The constructor can take multiple parameters. Inside of it you then call the special function Object (). Inside the brackets you put the propertiers you want the object to intialise with. In this case the property “a_property” with the value from the parameter.

Warning

Make sure that you don’t do more than just initialising properties. You can also put custom code in there, but sometimes you cannot use these constructors, so it is only recommended for making construction more convenient, not to put functionality in it. Do this in the construct block instead.

You can also define multiple constructors:

public class MyClass : Object {

    public MyClass (int a) {
        Object (a_property: a);
    }

    public MyClass.without_parameter () {
        Object ();
    }

    // ...
}

As you can see you need to give it another name, separated with a ..

Inheritance#

Inheriting from an existing class is not difficult:

public class AnotherClass : MyClass {
    public int new_property { get; set; }
}

You can still use all the members of the derived class as well as the new ones:

var a = new AnotherClass ();

a.my_method ();
a.a_property = 10;
a.new_property = -20;

Although there are a few things to consider:

  • When you add a method or property with the same name as in the derived class, use the new keyword. This hides the original one, so that it will always use the new method or property. Accessing the old one is possible through super().a_property.

Also useful#

  • A class can also not derive from any other class. Such classes are called “fundamental”. It looks then like that:

    public class MyClass {
        // ..
    }
    
  • A class can also have constants in its scope. They can have any access modifier.

    public class MyClass : Object {
        public const int A_CONSTANT_VALUE = 99;
    
        // ...
    }