summaryrefslogtreecommitdiffhomepage
path: root/vala.html.markdown
blob: 393578b014e2afd30d4af20046fcbb4d58d0b194 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
---
language: vala
contributors:
    - ["Milo Gilad", "https://github.com/Myl0g"]
filename: LearnVala.vala
---

In GNOME's own words, "Vala is a programming language that aims to bring modern programming language features to GNOME developers without imposing any additional runtime requirements and without using a different ABI compared to applications and libraries written in C."

Vala has aspects of Java and C#, so it'll be natural to those who know either.

[Read more here.](https://wiki.gnome.org/Projects/Vala)

```vala

// Single line comment

/* Multiline
Comment */

/**
* Documentation comment
*/

/* Data Types */

char character = 'a'
unichar unicode_character = 'u' // 32-bit unicode character

int i = 2; // ints can also have guaranteed sizes (e.g. int64, uint64)
uint j = -6; // Won't compile; unsigned ints can only be positive

long k;

short l;
ushort m;

string text = "Hello,"; // Note that the == operator will check string content

string verbatim = """This is a verbatim (a.k.a. raw) string. Special characters
(e.g. \n and "") are not interpreted. They may also be multiple lines long.""";

// String Templates allow for easy string formatting
string string_template = @"$text world"; // "$text" evaluates to "Hello,"

int test = 5;
int test2 = 10;
string template2 = @"$(test * test2) is a number."; // Expression evaluation

string template_slice = string_template[7:12]; // => "world"

// Most data types have methods for parsing.

bool parse_bool = bool.parse("false"); // => false
int parse_int = int.parse("-52"); // => -52
string parse_string = parse_int.to_string(); // => "-52"

/* Basic I/O */

stdout.printf(parse_string); // Prints to console
string input = stdin.read_line(); // Gets input from console

stderr.printf("Error message"); // Error printing

/* Arrays */

int[] int_array = new int[10]; // Array of ints with 10 slots
int better_int_array[10]; // Above expression, shortened
int_array.length; // => 10;

int[] int_array2 = {5, 10, 15, 20}; // Can be created on-the-fly

int[] array_slice = int_array2[1:3]; // Slice (copy of data)
unowned int[] array_slice_ref = int_array2[1:3]; // Reference to data

// Multi-dimensional Arrays (defined with a number of commas in the brackets)

int[,] multi_array = new int[6,4]; // 6 is the number of arrays, 4 is their size
int[,] multi_array2 = {{7, 4, 6, 4},
                       {3, 2, 4, 6},
                       {5, 9, 5, 1}}; // new int[3,4]
multi_array2[2,3] = 12; // 2 is the array, 3 is the index in the array
int first_d = multi_array2.length[0] // => 3
int second_d = multi_array2.length[1] // => 4

// Stacked arrays (e.g. int[][]) where array lengths vary are not supported.

// Multi-dimensional arrays cannot be sliced, nor can they be converted to one-
// dimensional.

int[] add_to_array = {};
add_to_array += 12; // Arrays can be dynamically added to

add_to_array.resize(20); // Array now has 20 slots

uint8[] chars = "test message".data;
chars.move(5, 0, 7);
stdout.printf((string) chars); // Casts the array to a string and prints it

/* Control Flow */

int a = 1;
int b = 2;
int[] foreach_demo = {2, 4, 6, 8};

while (b > a) { // While loop; checks if expression is true before executing
  b--;
}

do {
  b--;
}
while (b > a); // Do While loop; executes the code in "do" before while (b > a)

for (a = 0; a < 10; a++) { stdout.printf("%d\n", a); } // for loop

foreach (int foreach_demo_var in foreach_demo) {
  stdout.printf("%d\n", foreach_demo_var);
} // foreach works on any iterable collection

if (a == 0) {
  stdout.printf("%d\n", a);
} else if (a > 1) {
  stdout.printf("%d\n", a);
} else {
  stdout.printf("A is less than 0");
} // if-then-else

switch (a) {
  case 1:
    stdout.printf("A is 1\n");
    break;
  case 5:
  case 10:
    stdout.printf("A is 5 or 10\n");
    break;
  default:
    stdout.printf("???\n")
    break;
} // switch statement

/* Type Casting and Inference */

int cast_to_float = 10;
float casted_float = (float) cast_to_float; // static casting; no runtime checks

// For runtime checks, use dynamic casting.
// Dynamically casted objects must be the following:
// - Object's class is the same class as the desired type
// - Object's class is a subclass of the desired type
// - Desired class is an interface implemented by the object's class

float dyna_casted_float = cast_to_float as float // Won't compile

var inferred_string = "hello"; // Type inference

/* Methods (a.k.a. functions) */

int method_demo(string arg1, Object arg2) { // Returns int and takes args
    return 1;
}

// Vala methods cannot be overloaded.

void some_method(string text) { }
void some_method(int number) { }  // Won't compile

// To achieve similar functionality, use default argument values.

void some_better_method(string text, int number = 0) { }

some_better_method("text");
some_better_method("text", 12);

// varargs (variable-length argument lists) are also supported.

void method_with_varargs(int arg1, ...) {
    var varargs_list = va_list(); // gets the varargs list

    string arg_string = varargs_list.arg(); // gets arguments, one after another
    int int_vararg = varargs_list.arg();

    stdout.printf("%s, %d\n", arg_string, int_vararg)
}

string? ok_to_be_null(int? test_int) { } // "?" denotes possible null value

// Delegates

delegate void DelegateDemo(char char_a);

void delegate_match(char char_a) { // Matches DelegateDemo's signature
  stdout.printf("%d\n");
}

void call_delegate(DelegateDemo d, char char_b) { // Takes a delegate arg
  d(char_b) // calls delegate
}

void final_delegate_demo() {
  call_delegate(delegate_match); // Passes matching method as argument
}

// Lambdas (a.k.a. Anonymous Methods) are defined with "=>"

(a) => { stdout.printf("%d\n", a); } // Prints "a"

/* Namespaces */

namespace NamespaceDemo {
  // Allows you to organize variable names
  int namespace_int = 12;
}
namespace_int += 5; // Won't compile

using NamespaceDemo;
namespace_int += 5; // Valid

/* Structs and Enums */

struct Closet {
  public uint shirts; // Default access modifier is private
  public uint jackets;
}

Closet struct_init_1 = Closet(); // or Closet struct_init_1 = {};
Closet struct_init_2 = {15, 3};
var struct_init_3 = Closet() { // Type inference also works
  shirts = 15;
  jackets = 3;
}

enum HouseSize { // An example of an enum
  SMALL,
  MODERATE,
  BIG
}

/* Classes and Object-Oriented Programming */

class Message : GLib.Object { // Class Message extends GLib's Object
  private string sender; // a private field
  public string text {get; set;} // a public property (more on that later)
  protected bool is_digital = true; // protected (this class and subclasses)
  internal bool sent = false; // internal (classes in same package)

  public void send(string sender) { // public method
    this.sender = sender;
    sent = true;
  }

  public Message() { // Constructor
    // ...
  }

}

// Since method overloading isn't possible, you can't overload constructors.
// However, you can use named constructors to achieve the same functionality.

public class Calculator : GLib.Object {

    public Calculator() {
    }

    public Calculator.with_name(string name) {
    }

    public Calculator.model(string model_id, string name = "") {
      this.with_name(@"$model_id $name"); // Chained constructors with "this"
    }
    ~Calculator() { } // Only needed if you're using manual memory management
}

var calc1 = new Calculator.with_name("Temp");
var calc2 = new Calculator.model("TI-84");

// Signals (a.k.a. events or event listeners) are a way to execute multiple
// methods with the same signature at the same time.

public class SignalDemo : GLib.Object {
  public signal void sig_demo(int sig_demo_int); // Must be public

  public static int main(string[] args) {
    // main method; program does not compile without it

    var sig_demo_class = new SignalDemo(); // New instance of class

    sig_demo_class.sig_demo.connect((ob, sig_int) => { // Lambda used as handler
        stdout.printf("%d\n", sig_int); // "ob" is object on which it is emitted
      });

    sig_demo_class.sig_demo(27); // Signal is emitted

    return 0;
  }
}

// You may use the connect() method and attach as many handlers as you'd like.
// They'll all run at around the same time when the signal is emitted.

// Properties (getters and setters)

class Animal : GLib.Object {
  private int _legs; // prefixed with underscore to prevent name clashes

  public int legs {
    get { return _legs; }
    set { _legs = value; }
  }

  public int eyes { get; set; default = 5; } // Shorter way
  public int kingdom { get; private set; default = "Animalia"} // Read-only

  public static void main(string args[]) {
    rabbit = new Animal();

    // All GLib.Objects have a signal "notify" emitted when a property changes.

    // If you specify a specific property, replace all underscores with dashes
    // to conform to the GObject naming convention.

    rabbit.notify["eyes"].connect((s, p) => { // Remove the ["eyes"] for all
      stdout.printf("Property '%s' has changed!\n", p.name);
    });

    rabbit.legs = 2;
    rabbit.legs += 2;
    rabbit.eyes = 2;

  }
}

// Inheritance: Vala classes may inherit 1 class. Inheritance is not implicit.

class SuperDemo : GLib.Object {
  public int data1;
  protected int data2;
  internal int data3;
  private int data4;

  public static void test_method {  } // Statics can be called w/out an object
}
class SubDemo : SuperDemo {
  public static void main(string args[]) {
    stdout.printf((string) data1); // Will compile
    stdout.printf((string) data2); // Protected can be accessed by subclasses
    stdout.printf((string) data3); // Internal is accessible to package
    stdout.printf((string) data4); // Won't compile
  }
}

// Abstract Classes and Methods

public abstract class OperatingSystem : GLib.Object {
  public void turn_on() {
    stdout.printf("Booted successfully.\n");
  }
  public abstract void use_computer();
}

public class Linux : OperatingSystem {
  public override void use_computer() { // Abstract methods must be overridden
    stdout.printf("Beep boop\n");
  }
}

// Add default behavior to an abstract method by making it "virtual".

public abstract class HardDrive : GLib.Object {
  public virtual void die() {
    stdout.printf("CLICK-CLICK-CLICK\n");
  }
}
public class MyHD : HardDrive {
  public override void die() {
    return;
  }
}

// Interfaces: classes can implement any number of these.

interface Laptop { // May only contain abstracts or virtuals
  public abstract void turn_on();
  public abstract void turn_off();

  public abstract int cores; // Won't compile; fields cannot be abstract
  public abstract int cores {get; set;} // Will compile

  public virtual void keyboard() { // Virtuals are allowed (unlike Java/C#)
    stdout.printf("Clickity-clack\n");
  }
}

// The ability to use virtuals in Vala means that multiple inheritance is
// possible (albeit somewhat confined)

// Interfaces cannot implement interfaces, but they may specify that certain
// interfaces or classes must be also implemented (pre-requisites).

public interface CellPhone : Collection, GLib.Object {}

// You can get the type info of a class at runtime dynamically.

bool type_info = object is TypeName; // uses "is" to get a bool

Type type_info2 = object.get_type();
var type_name = type_info2.name();

Type type_info3 = typeof(Linux);
Linux type_demo = (Linux) Object.new(type_info3);

// Generics

class Computer<OperatingSystem> : GLib.Object {
  private OperatingSystem os;

  public void install_os(OperatingSystem os) {
    this.os = os;
  }
  public OperatingSystem retrieve_os() {
    return this.os;
  }
}

var new_computer = new Computer<Linux>();

/* Other Features */

// Assertions: crash if a statement is not true (at runtime)

bool is_true = true;
assert(is_true);

// Contract Programming

int contract_demo(int arg1, int arg2) {
  requires(arg1 > 0 && arg1 < 10) // Notice the lack of semicolon
  requires(arg2 >= 12)
  ensures(result >= 0)
}

// Error Handling

void error_demo(int int_ex) throws GError {
  if (int_ex != 1) {
    throw new GError("TEST MESSAGE");
  }
}
void error_demo2() {
  try {
    error_demo(0);
  } catch (GError ge) {
    stdout.printf("%s\n", ge.message);
  }
}

// Main Loop

void main() {

  var main_loop = new MainLoop();
  var time = new TimeoutSource(2000);

  time.set_callback(() => { // Executes the following lambda after 2000ms
      stdout.printf("2000ms have passed\n");
      main_loop.quit();
      return false;
  });

  time.attach(main_loop.get_context());

  loop.run();
}

// Pointers (manual memory management)

Object* pointer_obj = new Object(); // Creates Object instance and gives pointer

pointer_obj->some_method(); // Executes some_method
pointer_obj->some_data; // Returns some_data

delete pointer_obj;

int more = 57;
int* more_pointer = &i; // & = address-of
int indirection_demo = more_pointer*; // indirection

// Profiles: affect which Vala features are avaliable and which libraries the
// C-code will use.
// - gobject (default)
// posix
// dova
// Use "--profile=whatever" when compiling.

```
* More Vala documentation can be found [here](https://valadoc.org/).
* [Alternate construction syntax](https://wiki.gnome.org/Projects/Vala/Tutorial#GObject-Style_Construction) similar to GObject
* More on contract programming [here](http://en.wikipedia.org/wiki/Contract_programming)
* Collections library can be found [here](https://wiki.gnome.org/Projects/Vala/Tutorial#Collections)
* [Multithreading](https://wiki.gnome.org/Projects/Vala/Tutorial#Multi-Threading)
* Read about building GUIs with GTK+ and Vala [here](http://archive.is/7C7bw).
* D-Bus [integration](https://wiki.gnome.org/Projects/Vala/Tutorial#D-Bus_Integration)