Warum sollte man sich für Vala interessieren?
Vala ist eine relativ junge Programmiersprache welche 2006 von den Schweizern Jürg Billeter und Raffaele Sandrini entwickelt wurde. Das besondere an Vala ist das es über moderne Features
wie z.b. OOP / Lambda-Ausdrücke / Closures Feature verfügt und dabei eine relativ leichte und verständliche Syntax beinhaltet (relativ zu Java). Auf nervige Getter- und Setter-Methoden werden ebenso verzichtet wie auf das verkorkste Event System von Java. Vala erzeugt nativen Code mittels C, welche keine Laufzeitumgebung benötigt. Das Portieren der Vala Applikationen von Linux nach Windows ist mittels mingw leicht (Nach OSX direkt mittels gcc). Was Vala in diesem Zusammenhang auch besonders von anderen neuen Programmiersprachen wie etwa Go hervorhebt ist, das man auf sämtliche C- Bibliotheken zugreifen kann (weiteres dazu hier) und das macht gepaart mit den oberen vorteilen, Vala aus dem Stand heraus zu einer mächtigen Programmiersprache (IMHO). Unter Linux ist eine Entwicklungsumgebung verfügbar (Anjuta DevStudio) welche “out of the box” einen ordentlichen Code Editor, sowie einen WYSIWYG GTK-Editor mit sich bringt und natürlich Vala samt compiler und co. Leider nur für Linux. Die Vala Homepage mit noch mehr Informationen finden Sie hier.
Aus Sicht eines Java Entwicklers hat es weder SUN noch Oracle geschafft Java auf dem Desktop zu etablieren. Das liegt zum einen daran das die GUI Elemente (Swing) nie wirklich in die jeweilige Oberfläche gepasst haben. Dazu kommt das Java eine VM zum ausführen benötigt, welche vor allem beim ersten Programmstart langwierig geladen werden muss. Das sind dinge die mich persönlich nicht wirklich stören, aber viele Endanwender (mit Java EE sieht es natürlich ganz anders aus).
Dieser Blog wird auch zukünftig erweitert und verbessert (z.b. Inhaltsverzeichnis). Eingereichte Beiträge z.b. über das Thema Collections sind erwünscht ebenso wie Korrekturen.
Tutorial
Dieses Tutorial wurde übersetzt und basiert größtenteils auf der englischen Originalfassung von live.gnome.org
Quelldateien
Java: *.java
Vala: *.vala
Kompilierung
Java: kompiliert nach JVM byte code (.class files)
$ javac SourceFile1.java SourceFile2.java
Vala: kompiliert nach C welcher dann z.b. mit gcc nativ übersetzt wird.
$ valac source1.vala source2.vala -o program
Vala’s standard Objekt system ist GObject, kompilierte Vala Bibliotheken sind gültig für C-Bibliotheken.
Verwenden von Bibliotheken
Java: .jar files
$ javac -classpath foo-1.0.jar;bar-3.0.jar SourceFile.java
Vala: packages (C/Vala-Bibliotheken mit .vapi files)
$ valac --pkg foo-1.0 --pkg bar-3.0 source.vala
Es sind nur ASCII-Buchstaben für Bezeichner erlaubt. Sie können Vala Schlüsselwörter als Bezeichner verwenden, wenn sie mit dem Präfix @ beginnen. Das At-Zeichen wird nicht als Teil des Namens berücksichtigt.
Code-Organisation
Java: eine Toplevel-Klasse pro Datei, Dateinamen gleicht Klassennamen
Vala: eine Vala Quelldatei kann mehrere Klassen enthalten, Dateiname muss nicht der Name einer Klasse ähneln
Hierarchie
Java: packages, abgebildet in der Verzeichnis-Hierarchie, welche das Reverse Domain Name System repräsentieren
import javax.swing.*; package org.foo.bar;
Vala: namespaces, basiert nicht auf der Verzeichnis-Hierarchie, kein Reverse Domain Name System im Zusammenhang
using Gtk; // importiert die Gtk Bibliothek
namespace Foo.Bar {
// ...
}
Vala Namespaces können Methoden ohne Klassen enthalten. Sie sind implizit statisch.
Default Imports
Java: package java.lang.* default Import
Vala: namespace GLib default Import
Start Methode
Java: public static void main(String[] args)
Vala: static int main (string[] args)
Diese kann außerhalb einer Klasse und privat sein. Kann zurückkehrenden Exit-Code liefern (int), args-Argumente sind möglich.
Basis Typen
- grösse von (int, long, …) welche Architektur(CPU) abhängig ist.
Get size of a type in bytes with sizeof (), e.g. sizeof (int) - Zusätzliche Vala typen int8, int16, int32, int64 (signed), uint8, uint16, uint32, uint64 (unsigned) mit Architektur unabhängige und garantierten Größen
- kein byte (bei uint8, stattdessen int8)
- bool statt boolean
- zusätzliche Basis typen: unichar repräsentieren die Unicode character
Konstante modifier: const anstatt final.
Vala’s Basis Typen haben Methoden:
int a = -4.abs (); string s = a.to_string (); int b = int.max (5, 7); // statische Methoden können über 'int' aufgerufen werden.
Strings
Java
Datentype: String
Vergleichstest: str1.equals(str2)
Vala
Datentype: string (lower case)
Vergleichstest: str1 == str2
String vergleiche, vergleichen Inhalte keine Referenzen. Man kann strings lexikographisch
vergleichen mit <, >, <=, >= etc. Strings können mit switch genutzt werden.
Vala strings sind UTF-8 encoded.
Zusätzliche String Funktionen in Vala
Vala unterstützt “wörtliche” strings mit: """..."""
string verbatim = “”"Verbatim strings berücksichtigen keine escape Sequenzen
wie \n, \t, … und kann mehrere Zeilen umfassen.Die Zeilenumbrüche sind Teil
der strings. Sie können mit Anführungszeichen(“) und backslash (\)
innerhalb eines Wörtlichen-Strings ohne abschließendes (“”") sein.
Vala unterstützt string Templates mit: @"...". String Templates können Ausdrücke enthalten
mit vorangestellten $ Zeichen.
string name = "John"; stdout.printf (@"Welcome, $name!"); stdout.printf (@"3 + 2 = $(3 + 2)");
Arrays
dynamisches erweitern
Elemente können in Arrays dynamisch erweitert werden, indem Sie den Operator += nutzen. In Java ist dieses nicht möglich.
int[] squares = {};
for (int i = 0; i < 100; i++) {
squares += i * i;
}
Keine Größenüberprüfung
Es gibt zur Laufzeit keine Größenprüfung für Arrays in Vala:
int[] a = new int[10]; a[20] = 1; // Nicht sicher! (Optionale Größenprüfung geplant.)
Multi-Dimensionale Arrays
Java: multi-dimensional arrays [][] (arrays von arrays)
int[][] matrix = new int[3][];
for (int[] row : matrix) {
row = new int[4];
}
Vala: quadratisches multi-dimensional arrays [,], [,,], usw.. (zugeordnet als ein zusammenhängender Speicherblock)
int[,] matrix = new int[3,4];
Illustration: “quadratisches vs. zerklüftetes” multi-dimensionale arrays

Type Inference (Typrückschluss)
Vala unterstützt einen Mechanismus namens type inference (Typrückschlusses (implizite Typisierung)) für lokale Variablen: Lokale Variablen können mit dem “var” keyword statt der Typenbezeichnung begonnen werden, wenn der Compiler diese ableiten kann (infer). Dies hilft die Vermeidung unnötiger Redundanz und ist besonders nützlich für generische Typen. Beispiele:
var obj = new Object (); var map = new HashMap<string, int> (); var str = "hello, world"; var arr = new int[10];
Statt:
Object obj = new Object (); HashMap<string, int> map = new HashMap<string, int> (); string str = "hello, world"; int[] arr = new int[10];
Alles ist statisch typisiert.
Foreach
Java: for (int i : numbers) { }
Vala: foreach (int i in numbers) { }
Inheritance (Vererbung)
Java: extends, implements
public class Demo extends Foo implements Bar {
public Demo() {
super();
}
}
Vala: Doppelpunkt, gefolgt von Komma getrennte Auslistung, für Oberklassen und Schnittstellen
public class Demo : Foo, Bar {
public Demo () {
base ();
}
}
super heist in Vala base.
Objekt Basis Klasse
Java: implizite Vererbung (implicit inheritance) von Objekt (java.lang.Object)
public class Foo {
// ...
}
Vala: keine implizite Vererbung von Objekt (GLib.Object)
public class Foo : Object {
// ...
}
Was passiert wenn Sie nichts von einem Objekt erben? Nichts schlimmes. Diese Klassen werden etwas kleiner sein und es werden einige Funktionen wie z.B. Eigentumsänderung-Benachrichtigungen werden fehlen und Ihre Objekte werden nicht über eine gemeinsame Basisklasse verfügen. In der Regel bestimmen Sie selbst, was vom Objekt geerbt werden soll.
Methoden überladen
Java
public class Demo {
public void draw(String text) { }
public void draw(Shape shape) { }
/* Methodenüberladung und Verkettung für bequemes Methoden
/* überladen mit weniger Argumenten*/
void f(int x, String s, double z) { }
void f(int x, String s) {
f(x, s, 0.5);
}
void f(int x) {
f(x, "hello");
}
}
Vala: Keine Methoden Überladung stattdessen müssen unterschiedliche Methodennamen gewählt werden.
public class Demo : Object {
public void draw_text (string text) {
}
public void draw_shape (Shape shape) {
}
/* Method with argument default values */
void f (int x, string s = "hello", double z = 0.5) {
}
}
Vala unterschützt nicht das überladen von Methoden, da in Vala geschriebene libraries auch für C. Entwickler mit sinnvollen Funktionsnamen genutzt werden können.
Mehrere Konstruktoren
Java: constructor overloading (Konstruktor Überladung)
public class Foo {
public Foo() { }
public Foo(int foo) { }
public Foo(String bar) { }
}
new Foo();
new Foo(42);
new Foo("hello");
Vala: Benannten Konstruktor statt Konstruktor Überladung.
public class Foo : Object {
public Foo () { }
public Foo.with_foo (int foo) { }
public Foo.from_bar (string bar) { }
}
new Foo ();
new Foo.with_foo (42);
new Foo.from_bar ("hello");
Konstruktor Verkettung
Java: this()
class Foo {
public Foo() {
this("bar");
}
public Foo(string bar) {
}
}
Vala: this() oder this.name_addition()
class Foo : Object {
public Foo () {
this.with_bar ("bar");
}
public Foo.with_bar (string bar) {
}
}
Overriding (Methoden Überschreiben)
Java: Alle Methoden sind virtuell überschreibbar voreingestellt, final verhindert das überschreiben
public class Super {
public int myMethod(int x, int y) { }
public final void anotherMethod() { }
}
public class Sub extends Super {
@Override
public int myMethod(int x, int y) {
super.myMethod(x, y);
// ...
}
}
Vala: Alle Methoden sind nicht-virtuelle und nicht überschreibbar. Standardmäßig muss das Überschreiben explizit zugelassen werden. Umgekehrt zu Java.Vala nutzt das Schlüsselwort ”override”
statt “@Override” und ist nicht optional.
public class Super : Object {
public virtual int my_method (int x, int y) { }
public void another_method () { }
}
public class Sub : Super {
public override int my_method (int x, int y) {
base.my_method (x, y);
// ...
}
}
Access Modifiers (Zugriffsmodifizierer)
| Java | Vala |
| public | public |
| protected | protected |
| package-private (voreingestellt) | internal |
| private | private (voreingestellt) |
Obwohl private Standard ist, können Sie explizit Methoden public setzen.
Interfaces (Schnittstellen)
Java: interface Methoden sind implizit abstract
public interface Foo {
public void foo(int i);
public int bar(String s, double d);
}
Vala: abstract explizit notwendig
public interface Foo {
public abstract void foo (int i);
public abstract int bar (string s, double d);
}
Warum ist das so? Vala-Schnittstellen können nicht-abstrakte Methoden haben (dh. Methoden mit Implementierungen). Vala Schnittstellen können gemixt (eingeschränkte Form der Mehrfachvererbung) verwendet werden. Vala-Schnittstellen können statische Methoden, z. B. Factory-Methoden beinhalten.
Vala interface können statische (static) Methoden haben, z.b.. factory Methoden.
Java: interface inheritance (Interface Vererbung)
public interface IfaceA {
public void methodA();
}
public interface IfaceB extends IfaceA {
public void methodB();
}
public class Demo implements IfaceB {
public void methodA() { }
public void methodB() { }
}
Vala: interface Voraussetzung
interface IfaceA : Object {
public abstract void method_a ();
}
interface IfaceB : Object, IfaceA {
public abstract void method_b ();
}
class Demo : Object, IfaceA, IfaceB {
public void method_a () { }
public void method_b () { }
}
Schnittstellen in Vala können nicht von anderen Schnittstellen erben, aber sie können andere Schnittstellen Voraussetzungen deklarieren, welches etwa auf gleiche Weise arbeitet. Schnittstellen können auch Klassen als Voraussetzung haben. Dies wird oft verwendet um sicherzustellen, dass eine Instanz einer Schnittstelle auch eine Objekt-Unterklasse beinhaltet. Die Tatsache das Schnittstellen nicht von anderen Schnittstellen erben können ist meist nur eine technische Unterscheidung - in der Praxis funktioniert Valaś System genauso wie Javaś in diesem Bereich, aber mit dem zusätzlichen Feature von Voraussetzten (prerequsite) Klassen.
Enums (Aufzählungen)
Java: enums sind Klassen basiert.
Vala: enums sind integer basierend. Methoden erlauben, allerdings keine Konstruktoren, Felder, usw..
enum Season {
SPRING,
SUMMER,
AUTUMN,
WINTER;
public bool is_hot () {
return this == SUMMER;
}
}
Run-Time Type Information (Laufzeit Type Informationen)
Dynamische Typ überprüfung
Java: obj instanceof Foo
Vala: obj is Foo
Dynamisches Typ Casting (dynamische Typ Umwandlung)
Java: Foo foo = (obj instanceof Foo) ? (Foo) obj : null
Vala: Foo foo = obj as Foo
und natürlich, “(obj is Foo) ? (Foo) obj : null” funktioniert auch.
Getting Type Information (Type Informationen ermitteln)
Java
Class c = Foo.class; System.out.println(c.getName()); Foo = (Foo) c.newInstance();
Vala: typeof () operator
Type t = typeof (Foo);
stdout.printf ("%s\n", t.name ());
Foo o = (Foo) Object.new (t);
Object Destruction (Objekt Zerstörung)
Java: finalisiert, nicht deterministisch
public class Foo {
@Override
protected void finalize() {
}
}
Vala: destruktor, deterministisch
public class Foo : Object {
~Foo () {
}
}
Annotations
Java: @Annotations, selbst definierbar
Vala: Attribute sind im Compiler eingebaut. Syntax: [AttributeName (param1 = Wert, param2 = Wert)]. Vor allem für Bindungen oder D-Bus-Schnittstellen (Desktop-Kommunikation unter Linux) verwendet. Der prominenteste Attribut für Bindungen ist [CCode (...)]
Properties
Java: Bean Konvention, getX() und setX() Methoden
public class Person {
private int age = 32;
public int getAge() {
return this.age;
}
public void setAge(int age) {
this.age = age;
}
public static void main(String[] args) {
Person p = new Person();
p.setAge(p.getAge() + 1);
}
}
Vala: Sprachunterstützung für properties (Eigenschaften), get {} und set {} blöcke, können wie auf Felder zugegriffen werden, wodurch sich das ungeliebte getter und setter verhalten verbessert.
public class Person : Object {
private int _age = 32;
public int age {
get { return _age; }
set { _age = value; }
}
}
void main () {
var p = new Person ();
p.age++;
}
Oder noch kürzer für die Standard Implementation:
public class Person : Object {
public int age { get; set; default = 32 }
}
Delegates, Closures
Java: implementiert delegierte Muster, und nutzt anonyme innere Klassen
public interface MyDelegateType {
public void invoke(int a, double b);
}
public class Demo {
private static void foo(MyDelegateType deleg) {
deleg.invoke(32, 0.25);
}
public static void main(String[] args) {
MyDelegateType deleg = new MyDelegateType () {
public void invoke(int a, double b) {
System.out.println("a = " + a + "; b = " + b);
}
};
deleg.invoke(42, 0.75);
foo(deleg);
}
}
Vala: Vala unterstützt delegates und closures
delegate void MyDelegateType (int a, double b);
void foo (MyDelegateType deleg) {
deleg (32, 0.25); // invoke delegate
}
void main () {
MyDelegateType deleg = (a, b) => {
stdout.printf ("a = %d; b = %g\n", a, b);
};
deleg (42, 0.75); // aufruf von delegate
foo (deleg); // übergibt delegate einer Methode
}
Closures sind anonyme Methoden welche die Variablen des äußeren Geltungsbereichs erfassen. Sie können zugewiesene Variablen delegieren oder als delegierten Parameter an Methoden übergeben werden.
Sie können Methoden auch direkt zuweisen, um Variablen zu delegieren:
delegate int MyDelegateType (int a, double b);
int add (int a, int b) {
return a + b;
}
int sub (int a, int b) {
return a - b;
}
void main () {
MyDelegateType deleg = add;
int sum = deleg (2, 3);
deleg = sub;
int diff = deleg (8, 4);
}
Dies bedeutet, Methoden können in Variablen gespeichert werden und und wie Objekte übergeben werden.
Notification (Ereignis Benachrichtigung)
Java: listeners (implement observer pattern)
public interface ClickListener {
public void clicked(Clickable source);
}
public interface Clickable {
public void addClickListener(ClickListener l);
public void removeClickListener(ClickListener l);
}
public class MyButton implements Clickable {
private List<ClickListener> clickListeners;
public MyButton() {
this.clickListeners = new ArrayList<ClickListener>();
}
private void fireClickListeners() {
for (ClickListener listener : this.clickListeners) {
listener.clicked(this);
}
}
public void addClickListener(ClickListener l) {
if (l != null) {
this.listeners.add(l);
}
}
public void removeClickListener(ClickListener l) {
if (l != null) {
this.listeners.remove(l);
}
}
public void test() {
fireClickListeners(); // fire listeners
}
}
public class Demo {
private class MyClickListener implements ClickListener {
public void clicked(Clickable s) {
System.out.println("handler C");
}
}
public static void main(String[] args) {
MyButton b = new MyButton();
b.addClickListener(new ClickListener() {
public void clicked(Clickable s) {
System.out.println("handler A");
}
});
b.addClickListener(new ClickListener() {
public void clicked(Clickable s) {
System.out.println("handler B");
}
});
MyClickListener handlerC = new MyClickListener();
b.addClickListener(handlerC);
b.test();
b.removeClickListener(handlerC);
}
}
Vala: Arbeitet mit signalen (signal keyword, .connect() and .disconnect()) was den
Event Code kleiner und übersichtlicher macht.
public class MyButton : Object {
public signal void clicked ();
public void test () {
clicked (); // sende signal
}
}
void handler_c (MyButton source) {
stdout.printf ("handler C\n")
}
void main () {
var b = new MyButton ();
b.clicked.connect ((s) => stdout.printf ("handler A\n"));
b.clicked.connect ((s) => {
stdout.printf ("handler B\n")
});
b.clicked.connect (handler_c);
b.test ();
b.clicked.disconnect (handler_c);
}
Property Änderungsbenachrichtigung
Java
import java.beans.PropertyChangeListener;
import java.beans.PropertyChangeSupport;
public class DemoBean {
private final PropertyChangeSupport pcs = new PropertyChangeSupport(this);
private String title;
public String getTitle() {
return this.title;
}
public void setTitle(String title) {
String old = this.title;
this.title = title;
this.pcs.firePropertyChange("title", old, title);
}
public void addPropertyChangeListener(PropertyChangeListener listener) {
this.pcs.addPropertyChangeListener(listener);
}
public void removePropertyChangeListener(PropertyChangeListener listener) {
this.pcs.removePropertyChangeListener(listener);
}
public static void main(String[] args) {
DemoBean demo = new DemoBean();
demo.addPropertyChangeListener(new PropertyChangeListener() {
public void propertyChange(PropertyChangeEvent evt) {
System.out.println("Property " + evt.getPropertyName() + " changed");
}
});
demo.setTitle("hello");
demo.setTitle("world");
}
}
Vala: Unterklasse von Object hat ein Benachrichtigungs Signal
public class Demo : Object {
public string title { get; set; }
}
void main () {
var demo = new Demo ();
demo.notify.connect ((s, p) => stdout.printf ("Property %s changed\n", p.name));
demo.title = "hello";
demo.title = "world";
}
Sie können jedoch nicht alte Werte ermitteln.
Wenn Sie nur an einer Änderungsbenachrichtigung einer einzigen Eigenschaft interessiert sind, können Sie die folgende Syntax verwenden:
demo.notify["title"].connect ((s, p) => stdout.printf ("title changed\n"));
Benachrichtigungen über Änderungen können mit einem CCode Attribut tag sofort deaktiviert werden:
class MyObject : Object {
// notify signal is NOT emitted upon changes in the property
[CCode (notify = false)]
public int without_notification { get; set; }
// notify signal is emitted upon changes in the property
public int with_notification { get; set; }
}
Exceptions (Ausnahme verhalten)
Java: Klassen basierte exceptions
public class TemperatureException extends Exception {
}
public class TooColdException extends TemperatureException {
}
public class TooHotException extends TemperatureException {
}
public class ExceptionDemo {
private void method() throws TemperatureException {
throw new TooColdException("It's too cold!");
}
public static void main(String[] args) {
try {
method();
} catch (TemperatureException e) {
System.out.println(e.getMessage());
}
}
}
Vala: exceptions heissen errors und sind nicht Klassen basiert.
// error domain mit mehreren Fehlercodes anstelle von Exception-Klassen
errordomain TemperatureError {
TOO_HOT,
TOO_COLD
}
void method () throws TemperatureError {
// error domain, error code, error message
throw new TemperatureError.TOO_COLD ("It's too cold!");
}
// muss Abgefangen oder propagiert werden, wenn Compilerwarnung ignoriert wird.
try {
method ();
} catch (TemperatureError e) {
stderr.printf ("Error: %s\n", e.message);
}
Obwohl der Compiler Warnungen für Fehler ignoriert, führt es nicht zum Abbruch der Kompilierung. Dies ermöglicht Prototyping.
You can check the error code with is:
if (e is TemperatureError.TOO_COLD) {
// ...
}
Parameter Directions (Parameter Anweisung)
Vala Methoden haben bzw. verfügen über so genannte ref Argumente. Wenn ein Methoden Argument als out oder ref-Argument deklariert ist bedeutet, dass die Methode den Wert der übergebenen Variablen (nur Variablen können als out oder ref-argument weitergegeben werden) ändern und die Änderung auch gültig ist, nachdem die Methode zurück gegeben worden ist . Wenn die zu übergebene Variable von einem Referenz-Typ ist, kann die Methode den eigenen Verweis ändern (weist ein neues Objekt der Variablen statt nur Ändern des Zustands des übergeben Objekts zu).
Der Unterschied zwischen out und ref ist, dass eine übergebene Variable als Argument ref initialisiert werden muss, bevor sie an die Methode übergeben werden kann. Wenn eine Variable mit out Argument übergeben wird, muss sie nicht initialisiert werden und wird voraussichtlich erst von der Methode initialisiert werden.
Die Schlüsselwörter (out und ref) müssen sowohl bei der Definition als auch dem Methoden aufgerufen verwendet werden.
/* Die Methode benötigt ein normales Argument sowie "out" und "ref"
*/
void my_method (int a, out int b, ref int c) {
a = 20; // hat keine Auswirkungen außerhalb dieser Methode
// bisher wurde "b" nicht initialisiert
b = 30; // Initialisierung von 'b' beeinflusst die übergebene Variable
c = 40; // beeinflusst die Übergebene Variable
}
void main () {
int x = 2
int y; // darf ruhig nicht initialisiert sein da oben (out int b)... also out verwendet wird
int z = 4; // Muss initialisiert sein bevor sie als "ref" Argument übergeben wird
my_method (x, out y, ref z); // out und ref müssen auch beim Aufruf deklariert werden
stdout.printf ("%d %d %d\n", x, y, z); // => "2 30 40"
//"x" hat sich nicht verändert während 'y' und 'z' sich verrändert haben
}
Nullability (Null-Zulässigkeit)
In Vala können null Referenz Typen im Methoden-Kopf mit einem Fragezeichen (?) deklariert werden,
womit null Referenz Typen bei dem Methodenaufrufe gestattet werden.
void my_method (Object? a, Object b) { }
void main () {
my_method (null, new Object()); // allowed (first argument may be null)
my_method (null, null); // not allowed (second argument must not be null)
}
Es wird zur Laufzeit sowie beim compilieren auf null pointer getestet.
void main () {
string? a = "hello";
string b = a; // Error: 'a' darf null sein aber 'b" nicht.
}
Argument Checking
Java
void method(double d, int i, Foo foo) {
if (d < 0 || d > 1.0)
throw new IllegalArgumentException();
if (i < 0 || i > 10)
throw new IllegalArgumentException();
if (foo == null)
throw new IllegalArgumentException();
// ...
}
Vala: Referenz Typparameter werden implizit auf NULL Werte überprüft, wenn sie mit “?” markiert worden sind. So müssen sie nicht manuell auf null überprüft werden.
Methoden können Vorbedingungen haben:
void method (double d, int i, Foo foo)
requires (d >= 0.0 && d <= 1.0)
requires (i >= 0 && i <= 10)
{
// ...
}
Vala unterstützt zusätzlich Nachbedingungen (postconditions), z. B. zur Überprüfung des Rückgabewertes:
int square (int i)
ensures (result >= 0)
{
return i * i;
}
Ergebnis von return ist eine spezielle Variable, welchen den Rückgabe Wert darstellt.
Verwenden Sie Ausnahmebedingungen (errors) bei Laufzeitfehlern (Datenbank-Fehler, I/O Fehler),
Structs
Structs ist ein Konzept welches es in Java nicht gibt.
Beispiel:
JAVA:
class Point {
public int x;
public int y;
public Point (int x, int y) {
this.x = x;
this.y = y;
}
public void print () {
stdout.printf ("(%d, %d)", this.x, this.y);
}
}
VALA:
struct Point {
public int x;
public int y;
public Point (int x, int y) {
this.x = x;
this.y = y;
}
public void print () {
stdout.printf ("(%d, %d)", this.x, this.y);
}
}
Wie Sie sehen können, ist der einzige Unterschied das Schlüsselwort struct statt der Klasse. Allerdings haben struct-Typen unterschiedliche Bedeutungen als Klasse-Typen:
// Class var p1 = new Point (2, 4); // weist p1 dem heap zu var p2 = p1; // Zuweisung der Referenz p2.x = 3; p1.print (); // => (3, 4) p1 wurde ebenfalls verändert p2.print (); // => (3, 4) var p3 = new Point (3, 4); p2 == p3; // => false (selben Werte, aber verschiedene Referenzen)
// Struct var p1 = Point (2, 4); // Legt p1 auf den stack var p2 = p1; // kopie p2.x = 3; p1.print (); // => (2, 4) p1 ändert sich nicht p2.print (); // => (3, 4) var p3 = Point (3, 4); p2 == p3; // => true (gleiche Werte)
Synchronizing (Synchronisieren)
Java: synchronized
Vala: lock, kann nicht auf die ganze Methode angewendet werden, nur um member Objekte
Conditional Compilation (Bedingte Kompilierung)
Java: keine Bedingte Kompilierung
Vala: unterstützt #if, #elif, #else, #endif.
siehe Conditional Compilation
Speicherverwaltung
Java: Garbage collection
Vala: Automatische Referenzzählung
weiteres: Vala’s Memory Management Explained
statische Initialisierung
Java:
public class Foo {
static {
System.out.println("Static initializer block invoked.");
}
}
Vala: static construct { } block. Das erste mal wo eine Klasse oder eine Unterklasse davon instanziiert wird, wird dieser Code ausgeführt. Es wird garantiert dass dieser Code genau einmal in einem Programm läuft in der die Klasse instanziiert wurde.
class Foo : Object {
static construct {
stdout.printf ("Static constructor invoked.\n");
}
}
Additionally a Vala class can have a class construct { } block. This block will be executed once at the first use of its class, and once at the first use of each subclass of this class.
Varargs
Java:
String format(String pattern, Object... arguments) {
// ...
}
Vala: C-style varargs, not type-safe
string format (string pattern, ...) {
var l = va_list ();
// ...
}
Mehr Informationen im Vala Tutorial.
Nicht verfügbar im vergleich zu Java
- No final classes (planned as sealed classes)
- No static classes (use nested namespaces instead)
- No anonymous inner classes (use delegates + closures instead)
- No constraints on generic type parameters
- No implicit conversion of objects to strings (no general toString()). However, types that have a to_string() method are supported by string templates (@"...")
- No named breaks / labels
- No strictfp, transient keywords
Collections
Java: java.util.* package
Vala: Gee namespace, --pkg gee-1.0, http://live.gnome.org/Libgee
See Gee Examples, Gee Documentation
Vala ermöglicht Array-ähnlichen Zugriff mit hilfe der Gee Bibliothek (zB my_map[key] ist äquivalent zu my_map.get (key)). Vala unterstützt einen Operator für Collections in: x in my_collection entspricht my_collection.contains (x). Dieser Operator funktioniert auch mit Strings, obwohl Zeichenfolgen keine Kollektions sind.
IO, Network Sockets
Java: java.io.*, java.net.* packages
Vala: GLib namespace (imported by default), --pkg gio-2.0, GIO is part of GLib
See GIO Examples, GIO Networking Examples
Console Input / Output
Java
System.out.println("Hi!");
System.out.print("Please enter your name: ");
String name = System.console().readLine();
System.out.format("Welcome, %s!\n", name);
Scanner stdin = new Scanner(System.in);
System.out.print("Enter a string, a double, a float, and an int: ");
String s = stdin.next();
double d = stdin.nextDouble();
float f = stdin.nextFloat();
int i = stdin.nextInt();
System.out.println("You entered the following:");
System.out.println("String : " + s);
System.out.println("double : " + d);
System.out.println("float : " + f);
System.out.println("int : " + i);
Vala
stdout.printf ("Hi!\n");
stdout.printf ("Please enter your name: ");
var name = stdin.read_line ();
stdout.printf ("Welcome, %s!\n", name);
string s;
double d;
float f;
int i;
stdout.printf ("Enter a string, a double, a float, and an int: ");
stdin.scanf ("%s", out s);
stdin.scanf ("%lf", out d);
stdin.scanf ("%f", out f);
stdin.scanf ("%d", out i);
stdout.printf ("You entered the following:\n");
stdout.printf ("string : %s\n", s);
stdout.printf ("double : %lf\n", d);
stdout.printf ("float : %f\n", f);
stdout.printf ("int : %d\n", i);
Von Swing to GTK+
Einfache GUI App
Java
import javax.swing.*;
public class HelloWorldFrame extends JFrame {
public HelloWorldFrame() {
JLabel label = new JLabel("Hello World");
add(label);
setSize(100, 100);
}
public static void main(String args[]) {
JFrame frame = new HelloWorldFrame();
frame.setVisible(true);
}
}
Vala
using Gtk;
public class HelloWorldWindow : Window {
public HelloWorldWindow () {
var label = new Label ("Hello World");
add (label);
set_default_size (100, 100);
}
}
void main (string[] args) {
Gtk.init (ref args);
var win = new HelloWorldWindow ();
win.show_all ();
Gtk.main ();
}
Must be compiled with --pkg gtk+-3.0.
See GTK+ Examples
Transition Table
| Swing | GTK+ |
| JButton | Button |
| JCheckBox | CheckButton |
| JColorChooser | ColorSelection |
| JComboBox | ComboBox |
| JComponent | Widget |
| JDialog | Dialog |
| JEditorPane | TextView |
| JFileChooser | FileChooserDialog |
| JFrame | Window |
| JLabel | Label |
| JList | TreeView with ListStore |
| JMenu | Menu |
| JMenuBar | MenuBar |
| JOptionPane | MessageDialog |
| JPanel | Container (depending on layout: Box, Table, Fixed, …) |
| JPasswordField | Entry with visibility = false |
| JProgressBar | ProgressBar |
| JRadioButton | RadioButton |
| JScrollPane | ScrolledWindow |
| JSeparator | Separator |
| JSlider | Scale |
| JSpinner | SpinButton |
| JSplitPane | Paned |
| JTabbedPane | Notebook |
| JTable | TreeView with ListStore |
| JTextArea | TextView |
| JTextField | Entry |
| JTextPane | TextView |
| JToolBar | Toolbar |
| JToolTip | Tooltip |
| JTree | TreeView with TreeStore |
| JViewport | Viewport |