|
1 | 1 | # 3.2. Construction |
2 | 2 |
|
3 | | -Vala supports two slightly different construction schemes: the |
4 | | -Java/C#-style construction scheme which we will focus on for now, and |
5 | | -the GObject-style construction scheme which will be described in a |
6 | | -section at the end of the chapter. |
| 3 | +Vala supports two construction schemes that both target the same GObject type system: |
| 4 | +- Java/C#-style** constructors (named creation methods with bodies where you assign fields and call helpers) |
| 5 | +- GObject-style construction (`Object (...)`, **construct properties**, and `construct { }` blocks). |
| 6 | + |
| 7 | +They are equally central to writing GObject types; which you emphasize depends on the API you publish and how subclasses and bindings should interact with your type. |
| 8 | + |
| 9 | +When to use which?: |
| 10 | +- Prefer Java/C#-style constructors when you want familiar control flow, several ergonomic entry points via named constructors, and straightforward initialization in the constructor body. |
| 11 | +- Prefer GObject-style construction when you need construct-only properties, a single ordered initialization path that always runs (including for instances created via `Object.new` or language bindings), or alignment with GObject-based C libraries. |
| 12 | + |
| 13 | +Combining both is common in real code: named constructors provide a clear call surface and delegate configuration through `Object (property: value, ...)` while shared setup lives in `construct` blocks or construct properties. |
| 14 | + |
| 15 | +## Java/C#-style constructors |
7 | 16 |
|
8 | 17 | Vala does not support constructor overloading for the same reasons that |
9 | 18 | method overloading is not allowed, which means a class may not have |
10 | 19 | multiple constructors with the same name. However, this is no problem |
11 | | -because Vala supports **named constructors**. If you want to offer |
| 20 | +because Vala supports named constructors. If you want to offer |
12 | 21 | multiple constructors you may give them different name additions: |
13 | 22 |
|
14 | 23 | ```vala |
@@ -59,3 +68,79 @@ void main () { |
59 | 68 | var p2 = new Point.polar (5.7, 1.2); |
60 | 69 | } |
61 | 70 | ``` |
| 71 | + |
| 72 | +## GObject-style construction |
| 73 | + |
| 74 | +GObject-style construction matches how GObject builds instances in C. It introduces **construct properties**, a special `Object (...)` call, and a `construct` block. For example: |
| 75 | + |
| 76 | +```vala |
| 77 | +public class Person : Object { |
| 78 | +
|
| 79 | + /* Construction properties */ |
| 80 | + public string name { get; construct; } |
| 81 | + public int age { get; construct set; } |
| 82 | +
|
| 83 | + public Person (string name) { |
| 84 | + Object (name: name); |
| 85 | + } |
| 86 | +
|
| 87 | + public Person.with_age (string name, int years) { |
| 88 | + Object (name: name, age: years); |
| 89 | + } |
| 90 | +
|
| 91 | + construct { |
| 92 | + // do anything else |
| 93 | + stdout.printf ("Welcome %s\n", this.name); |
| 94 | + } |
| 95 | +} |
| 96 | +``` |
| 97 | + |
| 98 | +With this scheme, each construction method that participates centers on an `Object (...)` call for setting so-called **construct properties**. The `Object (...)` call takes a variable number of named |
| 99 | +arguments in the form of `property: value`. These properties must be |
| 100 | +declared as `construct` or `set` properties. They will be set to the |
| 101 | +given values and afterwards all `construct {}` blocks in the hierarchy |
| 102 | +from `GLib.Object` down to our class will be called. |
| 103 | + |
| 104 | +The `construct` block is guaranteed to be called when an instance of |
| 105 | +this class is created, even if it is created as a subtype. It does |
| 106 | +neither have any parameters, nor a return value. Within this block you |
| 107 | +can call other methods and set member variables as needed. |
| 108 | + |
| 109 | +Construct properties are defined just as `get` and `set` properties, and |
| 110 | +therefore can run arbitrary code on assignment. If you need to do |
| 111 | +initialization based on a single construct property, it is possible to |
| 112 | +write a custom `construct` block for the property, which will be |
| 113 | +executed immediately on assignment, and before any other construction |
| 114 | +code. |
| 115 | + |
| 116 | +If a construct property is declared without `set` it is a so-called |
| 117 | +**construct only** property, which means it can only be assigned on |
| 118 | +construction, but no longer afterwards. In the example above `name` is |
| 119 | +such a construct only property. |
| 120 | + |
| 121 | +Here's a summary of the various types of properties together with the |
| 122 | +nomenclature usually found in the documentation of gobject-based |
| 123 | +libraries: |
| 124 | + |
| 125 | +```vala |
| 126 | +public int a { get; private set; } // Read |
| 127 | +public int b { private get; set; } // Write |
| 128 | +public int c { get; set; } // Read / Write |
| 129 | +public int d { get; set construct; } // Read / Write / Construct |
| 130 | +public int e { get; construct; } // Read / Write-Construct-Only |
| 131 | +``` |
| 132 | + |
| 133 | +In some cases you may also want to perform some action - not when |
| 134 | +instances of a class are created - but when the class itself is created |
| 135 | +by the GObject runtime. In GObject terminology we are talking about a |
| 136 | +snippet of code run inside the `class_init` function for the class in |
| 137 | +question. In Java this is known as **static initializer blocks**. In Vala |
| 138 | +this looks like: |
| 139 | + |
| 140 | +```vala |
| 141 | +/* This snippet of code is run when the class |
| 142 | + * is registered with the type system */ |
| 143 | + static construct { |
| 144 | + ... |
| 145 | +} |
| 146 | +``` |
0 commit comments