Vala (programovací jazyk)
Projekt Vala je jedním z oficiálních projektů GNOME a usiluje o rozšíření možností vývoje nativně běžících aplikací o výhody, které jsou typické pro vývoj kódu kompilovaného do byte code (např. platforma Mono) a interpretovaného kódu (např. Python). V rámci projektu byl navržen programovací jazyk Vala. Součásti projektu ValaV rámci Valy je vyvíjen překladač Valy a navrhovány jazyky Vala a Genie. S projektem Vala úzce souvisí projekt aplikačního frameworku Dova. Jazyk Vala se velmi podobá jazyku C#. Většina rozdílů mezi oběma jazyky vyplývá ze zamýšleného odlišného principu překladu a ze zaměření Valy na platformu GNOME. Jazyk Vala je nejvýznamnějším jazykem projektu Vala. Překlad Valy neprobíhá obvyklým způsobem. Překladač zdrojový kód naparsuje a transformuje jej na strojový kód[2] v jazyce C, který je ekvivalentní původnímu zdrojovému kódu v jazyce Vala. Při této transformaci využívá v GNOME běžnou abstrakci typů přes GObjecty (GLib Object System). Získaný strojový kód v C je určen k překladu do zvoleného formátu spustitelných souborů (např. executable and linkable format (ELF)) ve standardním kompilátoru GCC jako běžný C zdrojový kód. Překladač vala compiler (program valac) umožňuje všechny tyto fáze překladu provést buď najednou, nebo provést pouze transformaci do zdrojového kódu v C. Vala se primárně zaměřuje na GNOME, které vyžaduje Linux nebo příbuzné UNIXové systémy. Přesto lze překlad Valy provést na jakémkoli systému, na kterém je dostupná knihovna GLib a překladač GCC nebo jeho porty. Jazyk Genie se inspiruje jazykem Python. Překlad zdrojového kód Genie je analogický překladu Valy. Význam Genie je okrajový. Jazyk Vala„Ahoj, světe!“Tento ukázkový minimální program typu Hello world vypíše řetězec "Ahoj". print("Ahoj");
Překladač valac tento kód uložený v souboru demo.vala během překladu transformuje na následující kód v jazyce C. Jeho uložení se provede příkazem "valac demo.vala -C". /* demo.c generated by valac 0.14.0, the Vala compiler
* generated from demo.vala, do not modify */
#include <glib.h>
#include <glib-object.h>
void _vala_main (void);
void _vala_main (void) {
g_print ("Ahoj");
}
int main (int argc, char ** argv) {
g_type_init ();
_vala_main ();
return 0;
}
Vstupní bod je při čistě objektově orientovaném programování statickou metodou hlavní třídy programu. Třídy jsou obvykle potomky GLib.Object (zkráceně jen Object). Následuje neminimalistický Hello World program v objektovém stylu: class Trida.AhojSvete : GLib.Object {
void pozdrav () {
stdout.printf ("Ahoj světe\n");
}
public static int main(string[] args) {
var objekt = new Trida.AhojSvete ();
objekt.pozdrav();
return 0;
}
}
Syntaxe a sémantika ValyZáklady syntaxe Valy, způsob komentování, nejběžnější operátory a predikáty (např. +, ++, %, <) a nejběžnější klíčová slova pro řízení průchodu kódem (např. for, if, while) se neliší od C, C++, Javy, C# a dalších podobných jazyků. Normou jazyka definované primitivní datové typy jsou prázdný typ (void), celé číslo (int, long, short, char), celé číslo s garantovaným platformově nezávislým rozsahem (int8, int16, int32, int64), pravdivostní hodnota (bool) s možnými hodnotami pravda (true) a nepravda (false), reálná čísla (float, double), reference na UTF-32 řetězec znaků (string), typ proměnné (Type). Dále Vala umožňuje programátorovi definovat vlastní:
Dále Vala obsahuje následující:
int kontrolovana_funkce(int hodnota)
requires (hodnota <= maximalni_povolena_hodnota)
requires (hodnota >= minimalni_povolena_hodnota)
ensures (result <= maximalni_teoreticky_mozny_vysledek)
{
// tělo funkce
}
void funkce_s_neznamym_poctem_argumentu(string fixed, ...) {
var seznam_argumentu = va_list();
string? klic;
string hodnota;
while (klic = l.arg()) {
hodnota = seznam_argumentu.arg();
stdout.printf("Argument jménem %s má hodnotu %s.", klic, hodnota);
}
}
Vala poměrně nečekaným způsobem pracuje s řetězci a zavádí operátor @.
/* ukázka použití operátoru @ a verbatim řetězce
vypisované řetězce jsou přepsané v komentářích
řetězce jsou vypisovány na samostatné řádky (řádkový zlom realizuje \n) */
static void main() {
int i = 1;
int j = 6;
stdout.printf(@"hodnota proměnné i (resp. j) a je $i (resp. $j)\n"); // hodnota proměnné i (resp. j) a je 1 (resp. 6)
stdout.printf(@"hodnota výrazu i + j je $(i + j)\n"); // hodnota výrazu i + j je 7
stdout.printf(@"špatně napsaný výraz $i+j\n"); // špatně napsaný výraz 1+j
string @for = "řetězec pojmenovaný klíčovým slovem for";
stdout.printf(@"Hodnota proměnné for je $(@for)\n"); // Hodnota proměnné for je řetězec pojmenovaný klíčovým slovem for
stdout.printf("Hodnota proměnné for je " + @for + "\n"); // Hodnota proměnné for je řetězec pojmenovaný klíčovým slovem for
stdout.printf("""verbatim řetězec vypíše "\\"\n """ + "\n"); //verbatim řetězec vypíše "\\"\n
}
Koncepce objektů ve Vala má tyto zvláštnosti:
Následující ukázkový kód demonstruje použití standardních getterů a setterů u vlastností prvni_mereni a druhe_mereni, definování vlastních getterů a setterů u vlastnosti mereni a různě pojmenované konstruktory. class mereni {
public double prvni_mereni {
private set;
get;
default = 0;
}
public double druhe_mereni {
internal set;
get;
default = 0;
}
public mereni.vycet(double prvni, double druhy) {
prvni_mereni = prvni;
druhe_mereni = druhy;
}
public mereni.stejna_hodnota(double hodnota) {
prumer = hodnota;
}
public mereni() {
}
public double prumer {
private set {
prvni_mereni = value;
druhe_mereni = value;
}
get {
return (prvni_mereni + druhe_mereni) / 2;
}
}
}
void main() {
var m = new mereni();
print(@"$(m.prvni_mereni)"); // vypíše defaultní hodnotu 0
m = new mereni.vycet(9.98,9.93);
m = new mereni.stejna_hodnota(10);
}
Vala umožňuje přistupovat ke konvenčně pojmenovaným metodám tříd přes speciální úspornou syntaxi. Nejčastěji se využívají indexery, přetypování na řetězec, řezy, definování iterátoru a definování prvků množiny. Použití ukazuje následující příklad. class priklad {
int[] i = {10,2,345,5,89};
public string? get(int index) {
if (index > 4)
return null;
return @"$(i[index])";
}
public void set(int index, int hodnota) {
i[index] = hodnota;
}
public int slice(long zacatek, long konec) {
int vysledek = 0;
for (int j = 0; j < 5; j++) {
if (j < zacatek)
continue;
if (j > konec)
break;
vysledek += i[j];
}
return vysledek;
}
public bool contains(int klic) {
for (int j = 0; j < 5; j++) {
if (i[j] == klic)
return true;
}
return false;
}
public string to_string() {
return @"$(i[0]) $(i[1]) $(i[2]) $(i[3]) $(i[4])\n";
}
public trida_iteratoru iterator() {
return new trida_iteratoru(this);
}
}
class trida_iteratoru {
int index = 0;
priklad p;
public bool next() {
if (index > 4)
return false;
return true;
}
public string? next_value() {
string vysledek = null;
if (index < 5)
vysledek = @"$(p[index])";
index++;
return vysledek;
}
public trida_iteratoru(priklad p) {
this.p = p;
}
}
void main() {
var p = new priklad();
print(@"$(p[1])\n"); //print(p.get[1]);
print(p.to_string()); //print(p.to_string());
p[1] = p[2:4]; //p.set(1, p.slice(0,3));
print(p.to_string());
print(11 in p); //print(p.contains(11));
print(p[100] ?? "neplatny index"); //p[100] == null ? p[100] : "neplatny index";
foreach (string s in p) {
print(s);
}
}
V rozumných případech již tyto metody přirozeně definuje norma jazyka. Konkrétně je předdefinováno převádění čísel na řetězec, řezy (slice) řetězců, iterátory u množin a podobně. Často používané řezy řetězců fungují ve Vale stejně jako v Pythonu. Dále Vala přináší různá experimentální rozšíření syntaxe. Například experimentální řetězení výrazů (chained relational expressions) umožňuje Množství další syntaxe a sémantiky nějakým způsobem přímo souvisí s použitím na platformě GNOME. Tomuto tématu se věnuje následující podkapitola. Integrace Valy s GNOMEVala následujícími způsoby využívá knihovnu GLib se systémem GObject.
public errordomain ChybaNejakehoTypu {
CODE_NEJAKY,
CODE_JINY,
CODE_OSTATNI
}
void generator_chyby() throws ChybaNejakehoTypu {
string popis_chyby;
// tělo funkce
if (podminka_nejaky())
throw new ChybaNejakehoTypu.CODE_NEJAKY(popis_chyby);
if (podminka_jiny())
throw new ChybaNejakehoTypu.CODE_JINY(popis_chyby);
if (podminka_ostatni())
throw new ChybaNejakehoTypu.CODE_OSTATNI(popis_chyby);
}
void funkce() {
try {
generator_chyby();
stdout.printf("vykonána funkce");
} catch (ChybaNejakehoTypu e) {
if(e is ChybaNejakehoTypu.CODE_OSTATNI)
continue; //chyby s tímto kodem ignoruji
stdout.printf(e.message);
} finally {
stdout.printf("vykonána funkce");
}
}
// příklad různých použití construct
class trida : Object {
public int vlastnost0 {
get;
set construct;
}
public int vlastnost1 {
get;
construct set;
} // táž definice jako vlastnost0
public int vlastnost2 {
get;
construct;
} // immutable vlastnost
// Dále by šlo použitý modifikátory přístupu anebo definovat vlastní settery/gettery
public trida(int i, int j, int k) {
Object(vlastnost0:i, vlastnost1:j, vlastnost2:k);
}
construct {
stdout.printf("Konstrukce třídy");
}
static construct {
stdout.printf("Registrace třídy");
}
}
void main() {
// v tomto okamžiku se vypíše "Registrace třídy"
trida t = new trida(12,16,-1); // v tomto okamžiku se vypíše "Konstrukce třídy"
t = new trida(0,5,0); // v tomto okamžiku se vypíše "Konstrukce třídy"
}
Další používané knihovna je Gee, která definuje datové kontejnery ArrayList, HashMap, HashSet a podobně. Každý typ má metodu read_only_view, která vrací snímek stavu kontejneru umožňující pouze čtení. Pro práci se vstupy a výstupy (např. diskové operace) se používá knihovna GIO. Práce s vlákny a časování spouštění kódu ve Vale staví na GLib. Asynchronní metody využívají knihovnu GIO:
K integraci s GNOME slouží i většina atributů kódu.
Při vývoji pokročilejších aplikací se vždy využívá populárních softwarových knihoven. Kompilace pak vyžaduje jisté vývojářské soubory a metainformace o knihovnách, které standardně spravuje systém pkg-config. Databázi pro utilitu pkg-config tvoří textové .pc soubory umístěné v adresáři /usr/lib/pkgconfig a v překrývajícím adresáři /usr/local/lib/pkgconfig. Příklad obsahu .pc souboru týkajícího se GTK+ je: prefix=/usr/local
exec_prefix=${prefix}
libdir=${exec_prefix}/lib
includedir=${prefix}/include
target=x11
gtk_host=i686-pc-linux-gnu
Name: GTK+
Description: GTK+ Graphical UI Library (${target} target)
Version: 2.18.0
Requires: gdk-${target}-2.0 atk cairo gio-2.0 pangoft2
Libs: -L${libdir} -lgtk-${target}-2.0
Cflags: -I${includedir}/gtk-2.0
Potřebné informace pro kompilaci vypíše příkaz Vala při překladu získává metainformací právě z pkg-configu (např. jména, umístění, softwarové závislosti). Rozhraní knihoven je "přepsáno" do Valy ve speciálních .vapi souborech. Tyto bindy se generují poloautomaticky utilitami vapigen a vala-gen-introspect. Vapi soubory jsou umístěny v adresáři /usr/share/vala/vapi/ a překrývající lokální adresář /usr/local/share/vala/vapi/. Bindy knihoven jsou rozčleněny do pěti větví.
V současnosti již existují bindy pro všechna důležitá rozhraní GNOME.[3] Následující demonstrační výstřižek kódu využívá knihovnu GTK+. Při kompilaci je nutné specifikovat jméno požadované knihovny GTK v systému pkg-config. Kód bude pravděpodobně kompilován proti nejnovější třetí hlavní verzi GTK ( using Gtk; // zapíná jmenný prostor Gtk
class zapnuti_gui : Object { //nejednoznačný zápis, Object může být Gtk.Object i GLib.Object
public zapnuti_gui() {
try {
var builder = new Builder (); //konstrukce třídy Gtk.Builder
builder.add_from_file ("gui.ui"); //konstrukce gui Gtk Builderem podle definice v gui.ui
}
}
}
Správa a ochrana pamětiVala umožňuje přímý přístup k paměti s pomocí ukazatelů. Z výkonnostní důvodů Vala nekontroluje platnost ukazatelů a rozsahů polí, proto čtení nebo zapisováním do nealokované paměti vyvolá přímo POSIXový signál segmentation fault. Algoritmus garbage collection je založen na prostém počítání referencí. Ve výjimečných situací se dá chování garbage collectoru upravit:
Klíčové slovo weak označuje referenci, která má být při počítání referencí ignorována. Klíčové slovo weak řeší typicky situaci, kdy reference vytvoří cyklus. V okamžiku, kdy není cyklus přerušen, existuje na každou referenci odkaz a tudíž nemůže být provedeno uvolnění paměti. Vlastnictví paměti určuje, která reference je rozhodná pro uvolnění paměti. Klíčové slovo unowned označuje referenci, která nevlastní paměť. Příklad pro použití demonstruje následující elementární kód. class Priklad {
private Object o;
public Object nevlastnena_reference() {
this.o = new Object();
return this.o;
}
}
Při odstraňování reference vrácené funkcí nevlastnena_reference() je uvolněn soukromý člen o, což může poškodit třídu. Člen o by měl být vlastněn třídou. Proto by funkce nevlastnena_reference měla mít následující prototyp. public unowned Object nevlastena_reference();
Vlastnictví převádí klíčové slovo owned. Atribut Compact označuje třídy, které nebudou registrovány a spravovány typovým systémem GLib. Atribut CCode s parametrem ref_function (resp. unref_function) u třídy určuje funkci, která se volá při vzniku (resp. zániku) reference na třídu. Porovnání s jazykem C#Jazyk Vala se podobá C# mnohem více než C++, Javě a jiným jazykům. Vala a C# se blíží k sobě například v následujících ohledech:
Hlavní rozdíly v samotných jazycích jsou:
V současnosti nejsou plně implementovány všechny vlastnosti jazyka Vala, které bude mít stabilní verze. V nejbližších verzích se předpokládá doimplementování vlastností přetěžování symbolů, iterátory (další význam klíčového slova yield), zapečetění třídy (klíčové slovo seal) a generických delegátů. Je pravděpodobné, že budoucí verze Valy rozšíří definici jazyka. Možnosti systému správy paměti budou pravděpodobně v dalších stabilních verzích Valy rozšířeny. Přidáním těchto nových rysů do Valy dojde k přiblížení Valy a C#. O přidání LINQ se neuvažuje. Existují dvě hlavní implementace jazyka C#. Originální .NET Framework je dostupná pouze pro operační systémy Microsoft Windows, čímž se míjí se zaměřením Valy na GNOME. Z důvodu odlišných cílových platforem si Vala a C# na .NETu přímo nekonkurují. Reimplementace .NETu framework Mono je dostupná i pro UNIXové operační systémy. Framework Mono je ve velké míře binárně kompatibilní s .NETem; výhodou Mona oproti Vale je možnost snadného portování na systémy Windows. Naopak nevýhody Mona z hlediska nasazení na GNOME jsou:
Předpokládá se, že v budoucnu Vala z GNOME zcela vytlačí C#/Mono. Vala softwareProjekt Vala se zatím nachází ve vývojových verzích, přestože je Vala už plně použitelná pro běžný vývoj. Ve Vale již byly vyvinuty některé aplikace převážně určené pro GNOME.[5] Vývoji softwaru ve Vale se věnuje GNOME Foundation. Příklady softwaru vytvořeného nadací ve Vale jsou:
Ve Vale je napsána také LaTeXila, editor pro TeX a LaTeX. Vývoji uživatelských aplikací ve Vale se věnovala nezisková organizace Yorba. Jejími produkty jsou prohlížeč obrázků Shotwell, plugin Valencia pro vývoj v jazyce Vala v Geditu, nelineární střižna videa Lombard a pokročilý multikanálový záznamník zvuku Fillmore.[6] Iniciativa Elementary OS vyvíjí linuxovou distribuci, v níž uživatelské aplikace budou napsány ve Vale.[7] Iniciativa vyvíjí nové uživatelské aplikace Postler (mailový klient), Maya (kalendář), Wingpanel a Plank (dockování aplikací), Slingshot (spouštěč), App Center (softwarové centrum), Marlin (souborový manažer), Devkit (vývojářský nástroj), Beatbox (hudební přehrávač) a přepisuje slovník Purple z Pythonu do Valy.[8] Zdrojový kód ve Vale lze vyvíjet například v již zmíněné Valencii, v Anjutě, MonoDevelop nebo prostředí Valaide. Při ladění programů napsaných ve Vale se dají pochopitelně nasadit i osvědčené pomůcky používané vývojáři v C/C++. Jazyk Genie
V roce 2008 Jamie McCracken představil jazyk Genie, který využívá projekt Vala.[9] Nepřesně řečeno Genie je jazyk Vala zapisovaný syntaxí jazyka Python. Přípona souborů se zdrojovým kódem je .gs. „Ahoj, světe!“Následující ukázkový minimální program typu Hello world vypíše řetězec "Ahoj". init
print "Ahoj" Knihovna GeeKnihovna Gee (Libgee – GObject collection library) se využívá ve Vale k práci s množinami, multimnožinami, frontami a další podobnými strukturami. Definovaná rozhraní jsou Iterable, Iterator, Map a Multimap. Od Itereble je odvozeno Collection, od kterého je odvozeno List, Set, Multist, Queue, Deque. Knihovna obsahuje různé implementace těchto rozhraní. Knihovna Gee je napsána ve Vale, a proto Gee spolupracuje s GLib a Gobjecty. Výhodou řešení je, že při ukládání/vybírání prvků a při destrukci objektů korektně funguje počítání referencí a mechanismus garbage collection. DovaDova je vysokoúrovňový aplikační framework napsaný výhradně v jazyce Vala. Projekt Dova se v současnosti nachází v rané fázi vývoje. Součásti projektu Dova jsou:
Překladač Vala
Oficiální překladač valac je jediným existujícím překladačem jazyka Vala. Chování překladače určují použité přepínače. Důležité přepínače například umožňují provést pouze kompilaci bez slinkování (přepínač -c), určit přepínače pro překlad mezikódu v jazyce C překladačem GCC (přepínač -X), uložit informace pro debuggování v GNU Debugger (přepínač -g), uložit vygenerovaný C kód (přepínač -C), určit umístění GObject-Introspection repository souborů (přepínač --gir a --girdir) nebo vytvořit .vapi soubor (přepínač --vapi). Překladač Valy je celý napsán ve Vale (tj. překladač má vlastnost self hosting). Bez překladače valac není možné iniciálně sestavit zdrojové kódy překladače valac. Proto balíček se zdrojovými kódy ve Vale obsahuje i překlad do strojového kódu[2] v jazyce C. Překlad lze provést několika způsoby. Různé implementace se vybírají volbou tzv. profilu glib, posix nebo dova (např. přepínač --profile=dova).
Profily posix a dova zatím neimplementují celý standard jazyka. Reference
Externí odkazy
|