Vala

Vala是一門面向對象的程式語言，由自舉編譯器產生C語言代碼和使用GObject系統，允許在GNOME運行時庫的基礎上使用大量現代的編程技巧。通過使用GLib和GObject，Vala提供了動態類型系統和基於引用計數（reference counting）系統的記憶體管理的功能。

## 描述

Vala是一門程式語言，結合了腳本語言的高級程式語言建造時間性能，與低級的程式語言運行時間性能。相較於用C寫成的應用和庫，它致力於將現代程式語言特徵帶給GNOME開發者，而不用強加任何額外的運行時間要求，並且不用使用不同的ABI。Vala的語法類似於C#，並為了更好的適應GObject類型系統而做了修改。

Vala由Jürg Billeter構想，並由他和Raffaele Sandrini實現，他希望開發GNOME應用能有對C語言的更高級替代者。他們的確喜歡C#的語法和語義，但不想使用Mono，故而他們在2006年5月完成了一個編譯器。最初它使用C來引導 (編譯器)，一年後（在2007年7月的版本0.1.0發行中），Vala編譯器實現了自舉。

## 版本歷史

版本｜發行日期｜注釋

o｜2006-07-15

o｜2007-07-09

o｜2010-09-18

o｜2013-05-27

o｜2015-09-18

o｜2018-05-12｜穩定長期支持

o｜2018-09-01

o｜2019-05-09

o｜2019-09-05

o｜2020-03-03｜穩定長期支持

o｜2020-09-10

c｜2021-01-11｜穩定長期支持

o｜2021-05-17

o｜2021-09-16

o｜2022-03-17｜穩定長期支持

c｜2022-09-16｜穩定長期支持

c｜2024-04-19｜穩定長期支持

l 舊版本只列入最初發行時間

## 語言設計

### 特徵

Vala使用GLib和它的子模塊（GObject、GModule、GThread、GIO）作為核心庫，它們支持多數作業系統，並提供：平台無關線程、輸入/輸出、文件管理、網路套接字、插件、正則表達式等。Vala的語法目前支持如下現代語言特徵：

- 接口
- 屬性
- 信號編程
- Foreach
- lambda表達式
- 局部變量的類型推論
- 泛型
- 空指針安全
- 輔助記憶體管理
- 異常處理

圖形使用者界面可以使用GTK部件工具箱和Glade 圖形使用者界面建造器來開發。

### 記憶體管理

對於記憶體管理，GType或GObject系統提供引用計數。在C語言中，編程者必須手工管理增加和移除引用，而在Vala中，管理這種引用計數是自動化的，如果編程者使用語言內建引用類型而非普通指針的話。唯一需要當心的是避免生成引用環，因為在這種情況下記憶體管理系統不能正確工作，此時需要使用Vala自帶的`week`關鍵字標註弱引用解決。

對於不支持引用計數的類型，Vala也支持按照生命周期自動釋放記憶體的非引用計數記憶體管理；Vala還可以通過指針手工記憶體管理。

### 綁定

Vala意圖提供但現存C庫的運行時間訪問，特別是基於GObject的庫，而不需要運行時綁定。要通過Vala使用一個由C語言編寫的庫，全部所需就是一個API文件（.vapi），包含採用Vala語法的類和方法聲明。但是不支持C++庫。目前在Vala的每次發行中，都包括了GTK以及大部份的GNU項目和GNOME平台的vapi文件。還有用Vala寫的一個庫叫做Gee，為常用數據結構提供基於GObject的接口和類。

為從用其他語言比如C#寫的應用訪問Vala庫，寫綁定生成器也應當是容易的，因為Vala解析器被寫為一個庫，所以所有運行時資訊在生成一個綁定的時候都是可獲得到的。

## 工具

### 編輯器

Vala的開發工具近些年來有了顯著改進。下面是具有支持Vala編程的插件的一些流行IDE和文本編輯器：

- GNOME Builder
- Visual Studio Code，具有Vala插件
- Vim，具有arrufat/vala.vim插件
- Emacs，具有vala-mode
- Atom
- Geany
- Kate

### 代碼智能

目前，有兩個活躍開發的語言伺服器為Vala提供了代碼智能：

- vala-lang/vala-language-server，設計用於支持LSP的任何編輯器，包括VSCode、vim和GNOME Builder。
- esodan/gvls，目前是Vala在GNOME Builder中的預設語言伺服器，它對支持LSP的任何編輯器提供支持。

### 建造系統

目前，有一些建造系統支持Vala，包括Automake、CMake、Meson等。

### 調試

對Vala程序的調試可以使用GDB或LLDB (調試器)。對於IDE：

- GNOME Builder擁有通過GDB的對Vala的內建調試支持。
- Visual Studio Code擁有對GDB和LLDB (調試器)的擴展，比如cpptools和CodeLLDB。

## 示範代碼

一個簡單的「Hello world」程序：

```vala
void main () {
    print ("Hello World\n");
}
```

### 面向對象

下面是更複雜的一個版本，表現了Vala的一些面向對象的特徵：

```vala
class HelloWorld: Object {
	private uint year = 0;

	public HelloWorld () {
	}

	public HelloWorld.with_year (int year) {
		if (year > 0)
			this.year = year;
	}

	public void greeting () {
		if (year == 0)
			print ("Hello World\n");
		else
			/* Strings prefixed with '@' are string templates. */
			print (@"Hello World, $(this.year)\n");
	}
}

void main (string[] args) {
	var helloworld = new HelloWorld.with_year (2021);
	helloworld.greeting ();
}
```

因為在GObject庫的情況下，Vala不支持多重繼承，但是Vala中的類可以實現任何數量的接口，它可以包含它們的方法的預設實現。下面一段代碼展示具有預設實現的Vala接口（有時稱為mixin）：

```vala
using GLib;

interface Printable {
	public abstract string print ();

	public virtual string pretty_print () {
		return "Please " + print ();
	}
}

class NormalPrint: Object, Printable {
	string print () {
		return "don't forget about me";
	}
}

class OverridePrint: Object, Printable {
	string print () {
		return "Mind the gap";
	}

	public override string pretty_print () {
		return "Override";
	}
}

void main (string[] args) {
	var normal = new NormalPrint ();
	var overridden = new OverridePrint ();

	print (normal.pretty_print ());
	print (overridden.pretty_print ());
}
```

### 信號和回調

下面是基本例子，展示如何定義一個信號於非緊湊（compact）的一個類中，它擁有用Vala通過GLib建造的一個信號系統。接著註冊回調函數到這個類的一個實例的這個信號。這個實例可以發送這個信號，而連接到這個實例的每個回調函數（也叫做處理器），將安它們連接上的次序來調用：

```vala
class Foo {
    public signal void some_event ();   // 定义一个信号

    public void method () {
        some_event ();                  // 发送这个信号（回调得以调用）
    }
}

void callback_a () {
    print ("Callback A\n");
}

void callback_b () {
    print ("Callback B\n");
}

void main () {
    var foo = new Foo ();
    foo.some_event.connect (callback_a);      // 连接回调函数
    foo.some_event.connect (callback_b);
    foo.method ();
}
```

### 線程

在Vala中新線程是代碼的一部份，比如要求在運行時間並發執行的一個函數。新線程的創建和同步是用時GLib中的`Thread`類完成的，它在創建新線程時接受一個函數作為參數，如下面（非常簡化的）例子所示：

```vala
int question(){
    // 一些print操作
    for (var i = 0; i < 3; i++){
        print (".");
        Thread.usleep (800000);
        stdout.flush ();
    }

    return 42;
}

void main () {
    if (!Thread.supported ()) {
        printerr ("Cannot run without thread support.\n");
        return;
    }
    print ("The Ultimate Question of Life, the Universe, and Everything");
    // 泛型参数是返回值的类型
    var thread = new Thread<int> ("question", question);

    print(@" $(thread.join ())\n");
}
```

### 圖形使用者界面

使用GTK來創建一個圖形使用者界面的"Hello, World!"程序：

```vala
int main (string[] args) {
    var app = new Gtk.Application (
        "com.example.App",
        ApplicationFlags.DEFAULT_FLAGS
    );

    app.activate.connect (() => {
        var win = new Gtk.ApplicationWindow (app) {
            title = "Hello, World!",
            default_width = 350,
            default_height = 70
        };

        var label = new Gtk.Label ("Hello, World!");
        win.child = label;
        win.present ();
    });
    return app.run (args);
}
```

在GTK 4平台上，需要以下命令來編譯這一示例:

```bash
valac --pkg gtk4 hellogtk.vala
```

## 參見

- Genie，基於Vala編譯器的具有近似Python語法的一種語言。
- Shotwell，用Vala寫的圖片組織器。
- Geary (軟體)，用Vala寫的郵件客戶端。
- elementary OS，具有大多用Vala編程的桌面環境的Linux發行版。
- Budgie，大多用Vala編程的Linux桌面環境。

## 外部連結

- The Vala Programming Language, on GNOME Live!
- Vala 語言書籍《Introducing Vala Programming》 （Apress / Amazon）
- 面向 Java 開發者的Vala 特性介紹
- 面向 C# 開發者的 Vala 特性介紹
- Benchmark of Vala versus C# and C
- Vala 語言編程規範（Geary版）
- Vala 的語言伺服器（Language Server Protocol）項目： VLS， GVLS
- Vala 語言社區： The Vala community on GitHub
- Vala 語言案例列表
- Vala 語言開發的資料庫管理工具： DBKangaroo
- Vala 語言庫：官方庫
- Vala 語言庫：第三方庫

## 基本資料

- 編程范型：面向對象、結構化、指令式
- 發行時間：2006年
- 開發者：Jürg Billeter, Raffaele Sandrini
- 軟體版本週期：0.56.3
- 類型系統：靜態類型, 強類型
- 受影響於：C, C++, C#, D, Java, BOO
- 作業系統：所有支持GLib的平台
- 許可證：GNU寬通用公共許可證2.1+
- 文件擴展名：.vala, .vapi