4.5. Compact Classes

Vala has three types of class: GObject subclasses, GType classes and compact classes. The relevant parts of a non-GLib based C library can be bound to a compact class in Vala.

4.5.1. Singly-Owned Classes

The most common case is the singly-owned compact class, which follows one of these patterns:

typedef struct foo Foo;
/* Create a new Foo handle. */
Foo *foo_make(void);
/* Make a copy of a Foo. */
Foo *foo_dup(Foo*);
/* Free a Foo handle. */
void foo_free(Foo*);

typedef struct bar *Bar;
/* Open a new Bar from a file, NULL if an error occurs. */
Bar bar_open(const char *filename);
/* Dispose of a Bar when finished. */
void bar_close(Bar);

These should both be bound as compact classes. The foo_make and bar_open functions will allocate memory and create a new instance of the type (this is where documentation is helpful). There’s an important subtle difference between these two: where the pointer is mentioned. In the case of Foo, the pointer is mentioned in every function, while Bar has it baked into the typedef. Vala will always add a star, so Bar will be actually be bound using struct bar.

The second difference is the constructor: Foo’s constructor will not fail, but Bar’s might fail. Vala constructors are not permitted to return null. Bar’s constructor is best bound as a static method, as these can return null.

[CCode (cname = "Foo", free_function = "foo_free")]
[Compact]
public class Foo {
    [CCode (cname = "foo_make")]
    public Foo ();

    [CCode (cname = "foo_dup")]
    public Foo dup ();
}

[CCode (cname = "struct bar", free_function = "bar_close", has_type_id = false)]
[Compact]
public class Bar {
    [CCode (cname = "bar_open")]
    public static Bar? open (string filename);
}

In case explicit duplication is needed, include a member function of the copy function called dup(), if available.

4.5.2. Reference-Counted Classes

Reference-counted classes usually have a pattern as follows:

typedef struct foo Foo;
Foo *foo_new();
Foo *foo_retain(Foo*);
void foo_release(Foo*);

and should be bound as:

[CCode (cname = "foo", ref_function = "foo_retain", unref_function = "foo_release")]
[Compact]
public class Foo {
    [CCode (cname = "foo_new")]
    public Foo ();
    [CCode (cname = "foo_retain")]
    public void @ref ();
    [CCode (cname = "foo_release")]
    public void unref ();
}

The ref and unref function are provided as a courtesy to the user such that they might manually change the reference counts in difficult situations.