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.

Vala
Paradigmapřevážně objektově orientovaný, multiparadigmatický
Vznikl v2006
AutorJürg Billeter, Raffaele Sandrini a další
Vývojářkomunita Valy, GNOME Foundation
Poslední verze0.52.3 (1. května 2021)
Typová kontrolasilné, statické
Hlavní implementaceprofily překladu glib, posix a dova
Dialektylze zapnout experimentální syntaxi
Ovlivněn jazykyC++, různá API GNOME, C#, Python[1]
Ovlivnil jazykyGenie
OSurčeno pro GNOME, teoreticky multiplatformní
LicenceLGPL 2.1 a novější verze

Součásti projektu Vala

V 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ď na jednou, 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 Valy

Zá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í:

  • struktury (struct), výčty (enum),
  • třídy (class), rozhraní (interface),
  • jmenné prostory (namespace),
  • iterátory,
  • typy delegátů. Delegáty (delegate) jsou jiný, praktičtější zápis ukazatelů na funkce známých z jazyka C.
  • Atributy kódu a mnohé další výrazové prostředky především souvisejí s použitím na platformě GNOME. Atribut kódu se zapisuje před svůj kód ve tvaru [nazev_atributu(prvni_parametr="hodnota", druhy_parametr="hodnota", treti_parametr="hodnota")].

Dále Vala obsahuje následující:

  • Všechny celočíselné typy mají znaménkovou hodnotu (např. int) a bezznaménkovou hodnotu značenou prefixem u (např. uint).
  • Vala umožňuje automatické zjišťování typů (type inference). Klíčové slovo var nahrazuje typ, který jednoznačně vyplývá z kontextu celého zdrojového kódu.
  • Vala umožňuje zápis anonymních funkcí s pomocí lambda výrazu reprezentovaným operátorem =>. Anonymní funkce jsou ve Vale reálný uzávěr.
  • Každý typ má nullovatelnou a nenullovatelnou variantu. Název nullovatelné varianty má jako příponu otazník (např. string?).
  • Vala má neomezenou pointerovou aritmetiku podobně jako např. C++. Podobně jako v C++ jsou pole jiný, praktičtější zápis pointerové aritmetiky. Tedy pole jsou ukazatele a zápisy x[i] je synonymem k *(x + i).
  • Operátor koalescence je označen dvěma otazníky ??.
  • Funkce může měnit hodnotu proměnné z hlediska volajícího kontextu. Takto měněné parametry funkce musí být označeny klíčovými slovy out nebo ref. Klíčové slovo out označuje proměnnou, která je funkci předána neinicializovaná a kterou funkce pro volající stranu inicializuje. Klíčové slovo ref označuje proměnnou, která je funkci předána inicializovaná.
  • Programátor může zadat do definice funkce podmínky, které podle teoretického rozboru jsou nesplněny pouze při nekorektním běhu programu. Při nesplnění podmínek je program ukončen. Následující příklad ukazuje použití klíčových slov requires, ensures a result. Klíčové slovo requires (resp. ensure) označuje výraz typu bool, který musí být splněn při vstupu do (resp. při skončení) funkce. Klíčové slovo result je hodnota vracená funkcí používaná k zapsání ensures podmínky.
int kontrolovana_funkce(int hodnota)
    requires (hodnota <= maximalni_povolena_hodnota)
    requires (hodnota >= minimalni_povolena_hodnota)
    ensures (result <= maximalni_teoreticky_mozny_vysledek)
{
    // tělo funkce
}
  • Datový typ typu proměnné lze získat operátorem typeof, známým z jazyka C (dialektu užívaným standardním kompilátorem GCC). Operátor is zjišťuje, zda lze provést přetypování. Při využití GLib registrace typů typů vrací metoda get_type() typ třídy. Operátor as slouží k snadnému zápisu dynamického přetypování; A as B je přehlednější zápis A is B ? (A) B : null;. K explicitnímu přetypování nullovatelného typu na korespondující nenulovatelný typ se používá zápis (!) promenna.
  • Vala podporuje generické programování, k jehož zápisu používá obvyklou syntaxi s lomenými závorkami.
  • Vala podporuje v definici parametrů funkce výpustku značenou ve stylu jazyka C třemi tečkami. Seznam názvů parametrů se získá funkcí va_list() a zadaný parametr v definici funkce uvádí typ hodnot parametrů.
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 @.

  • V řetězcích uvozených operátorem @ se názvy proměnných a výrazy uzavřené závorkou následující za znakem $ vyčíslují.
  • Z důvodů interoperability kódu ve Vale se zdrojovými kódy a knihovnami v jiných jazycích může vynucovat konkrétní pojmenování proměnných a jiných uživatelem definovaných symbolů. V této situaci může dojít ke kolizi pojmenovaní proměnných s klíčovými slovy Valy. Prefix @ způsobuje, že parser Valy klíčové slovo interpretuje jako běžný identifikátor.
  • Ve verbatim řetězcích (oddělovač """) nedochází k escapování znaků.
/* 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:

  • Vedle běžných modifikátorů přístupu public, private a protected existuje další modifikátor internal. Internal slouží k zpřístupnění symbolu pouze v rámci jednoho balíčku. Například internal skryje proměnné VAPI souboru před uživatelskou aplikací.
  • Lze definovat vlastnosti a jejich gettery a settery.
  • Není podporována vícenásobná dědičnost. Rodičovská třída se označuje klíčovým slovem base.
  • Vala umožňuje různé pojmenování konstruktorů a destruktorů. I přesto, že je použita automatická správa paměti, lze volat destruktor explicitně. Destruktor je od konstruktoru odlišen obvyklým prefixem ~.

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 (a < b) && (b < c) && (c < d) && (d < e) zapsat jednoduše jako a < b < c < d < e. Jednotlivá experimentální rozšíření jsou dostupná pouze při použití příslušných přepínačů při překladu.

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 GNOME

Vala následujícími způsoby využívá knihovnu GLib se systémem GObject.

  • Ke správě paměti a definování typů.
  • Vala přebírá z GLib systém GError řešící problematiku výjimek. Ve Vale se vygenerovaná výjimka (error) skládá z domény (domain), kódu (code) a zprávy (message). Domény a kódy jsou deklarovány klíčovým slovem errordomain. Popis chyby je programátorem libovolně zvolený řetězec. Práci s chybami ukazuje následující kód.
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");
    }
}
  • Označením funkce klíčovým slovem signal se z funkce stává i GLib signál. Signál má metodu connect, která registruje obsluhu signálu. Vlastnosti GLib signálu se definují atributy kódu (např. [Signal (action=true, no_recurse=false)] signal void nejaky_signal();).
  • Jmenuje-li se funkce v GLib g_neco0_neco1_neco2, pak se tato funkce jmenuje ve Vale GLib.Neco0.Neco1.neco2(). Podle této konvence se označují symboly GLib ve Vale.
  • V praxi se ve Vale často používají například funkce GLib pro asserci (např. warn_if_reached).
  • Výstupní proudy stdout, stderr jsou součástí GLib.
  • Ve Vale se obvykle třídy odvozují od GLib.Object (skrácený zápis Object).
  • K introspekci lze použít rozhraní GObject introspection.
  • Zdrojový kód definovaný ve třídě ve tvaru snippetu static construct { ...tělo... } se namapuje na funkci class_init() systému GObject. Tento kód se spouští při registraci třídy v běhovém prostředí GObject. Tato funkcionalita se hodí například k obnovení stavu perzistentních statických proměnných.
  • Snippet ve tvaru construct { ...tělo... } se rovněž namapuje na funkce GLib a spouští se vždy při konstrukci. Object umožňuje konstrukci "GObjectovým způsobem". Vlastnosti jsou inicializovány přes kód označeny slovem construct. Tento bod platí pouze pro potomky třídy GLib.Object.
// 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:

  • Třída vláken je Thread z knihovny GLib.
  • GLib řadí požadavky na provedení do smyček (posloupností), přičemž provedení se dá naplánovat na konkrétní okamžik. Z Valy je možné tento systém ovládat, což se dá využít při psaní aplikací s frameworky využívající GLib (např. GTK+ aplikací).
  • Zámky se zapisují ve tvaru lock (monitor){ ... }.
  • Provádění asynchronních metod lze přerušit. Asynchronní metody se označují klíčovým slovem async.
  • Asynchronní funkce umožňuje přidružit AsyncReadyCallback, která se vykoná asynchronně po skončení funkce. Zápis je asynchroni_funkce.begin(parametr, kod_AsyncReadyCallback_funkce(obj, res)).
  • Při dosažení kódu označeného klíčovým slovem yield se asynchronní funkce přeruší. V jejím výkonu se pokračuje až v okamžiku, kdy ji smyčka znovu naplánuje.
  • Obsluha se dá naplánovat mimo hlavní smyčku (MainLoop), což de facto způsobí vykonání na pozadí s nízkou prioritou. Syntaxe je Idle.add(funkce());.

K integraci s GNOME slouží i většina atributů kódu.

  • Změny dat zapouzdřených v třídě s atributem kódu [DBus(name = "specifikace_umisteni")] se automaticky exportuje na určenou lokální (nesystémovou) sběrnici běžícího D-Bus.
  • Vhodné vývojářské nástroje (např. Glade3) přečtou atributy kódu. Například kód dokumentuje atribut [Description(nick = "stručná charakteristika", blurb = "výstižný popis")].
  • Přes atribut CCode se odkazuje externí kód. Atribut CCode nabízí množství parametrů. Příkladem použití je [CCode (cname = "požadovaný_vapi_soubor")].

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 pkg-config --cflags --libs gtk+-2.0. Příkladem použití je gcc `pkg-config --cflags --libs gtk+-2.0` zdrojovy_soubor.c.

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í.

  • Ve větvi external jsou příspěvky od třetích stran, kteří nejsou vývojáři Valy ani příslušné knihovny.
  • Ve větvi upstream jsou bindy uvolněné vývojáři příslušné knihovny.
  • Větev experimental prakticky není otestována. Distribuce probíhá přes balík překladače valac.
  • Větev unstable je nedostatečně otestována. Distribuce probíhá přes balík překladače valac.
  • Větev stable je dostatečně otestována. Distribuce probíhá přes balík překladače valac.

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 (valac --pkg gtk+-3.0 jmeno_souboru.vala) nebo proti častěji používané druhé verzi (valac --pkg gtk+-2.0).

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ěti

Vala 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:

  • použitím klíčových slov weak, unowned, owned,
  • definováním a explicitním voláním destruktoru/destruktorů třídy,
  • atributem třídy compact,
  • předefinováním standardních ref_function a unref_function funkcí s pomocí atributu CCode.

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:

  • Většina nejdůležitějších klíčových slov se v obou jazycích shoduje. Klíčová slova se stejným nebo podobným významem v obou jazycích jsou abstract, as, base, bool, break, case, catch, char, class, const, default, delegate, do, double, else, enum, continue, false, finally, float, for, foreach, if, in, int, interface, internal, is, lock, long, namespace, new, null, object, out, override, private, protected, public, ref, return, sealed (plánováno do budoucích verzí Valy), sizeof, short, static, string, struct, switch, this, throw, true, try, typeof, uint, ulong, using, var, virtual, void a yield. Klíčová slova "navíc" v C# jsou např. byte, checked, decimal, event, explicit, extern, fixed, goto, implicit, operator, params, readonly, sbyte, stackalloc, unchecked, unsafe, ushort a volatile. Klíčová "navíc" ve Vale jsou např. async, construct, ensures, errordomain, int8, int16, int32, int64, owned, requires, signal, throws, Type, uint8, uint16, uint32, uint64, unichar, unowned, value, weak a některá označení funkcí implementovaných v knihovnách (např. assert z knihovny GLib).
  • Oba jazyky zavádějí nullovatelné typy, delegáty, neexistuje vícenásobná dědičnost, operátor koalescence, události/signály (v Vale signal, v C# event), stejnou syntaxi lambda výrazů, prefix @ při použití klíčového slova jako identifikátoru.
  • Oba jazyky jsou navrženy jen pro jednu platformu. Vala je optimalizována pro GNOME, C# pro .NET.

Hlavní rozdíly v samotných jazycích jsou:

  • Vala je v mnoha ohledech rozšířena a přizpůsobena pro platformu GNOME.
  • Kvůli výkonnostní optimalizaci Valy je implementován pouze neplnohodnotný garbage collector založený na počítání referencí. Pro problematické situaci zacyklení referencí zavádí Vala speciální syntaxi jako například možnost přímého zavolání destruktoru.
  • Autoři Valy doporučují úplně jiné jmenné konvence než autoři C#. Tato odlišnost vyplývá ze skutečnosti, že Vala primárně cílí na GNOME a C# primárně cílí na Microsoft Windows.
  • Z důvodu výkonnostních optimalizací Vala nekontroluje přístup do paměti, což umožňuje přistupovat i k nealokované paměti a vyvolat segmentation fault.
  • Vstupní bod programu je ve Vale funkce main, která může být definována mimo třídu.
  • Způsob překladu umožňuje zdrojový kód ve Vale přímočaře kombinovat se zdrojovým kódem v C/C++.
  • Nejdůležitějším jmenným prostorem ve Vale je prostor GLib, který nahrazuje prostor System v C#.
  • Samotná Vala dává omezené možnosti introspekce. Introspekce ve Vale by totiž měla být prováděna přes systém GObjectů (rozhraní GObject Introspection).
  • Vala neobsahuje LINQ.
  • Kontejnerové typy jako množiny jsou ve Vale řešeny knihovnou Gee. Tato knihovna je známou implementací kontejnerů pro systém typů GObject. Hlavní rozhraní pro vstupně-výstupní operace je ve Vale knihovna GIO.
  • Soubory se zdrojovým kódem ve Vale mají koncovku .vala.

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:

  • Programy využívající Mono mají výrazně vyšší hardwarové nároky. V případě běžných algoritmů je často Mono několikanásobně pomalejší než Vala.[4]
  • Platforma Mono je "prorostlá" částmi kódu čerpajícího z duševního vlastnictví autora .NETu, společnosti Microsoft. Licencování těchto částí mají korektně vyřešené pouze klienti společnosti Novell, která uzavřela exkluzivní bilaterální dohody s Microsoftem o spolupráci.
  • Běhové prostředí Mono mnozí (především komerční) distributoři Linuxu bojkotují. Konkrétně například u nejprodávanější komerční distribuce Red Hat Enterprise Linux (RHEL) distributor Red Hat prostředí Mono zcela ignoruje.
  • Prostředí Mono je reimplementací .NETu, jehož návrh je optimalizován pro Windows. Na rozdíl od Valy není Mono optimalizované pro GNOME.
  • I malý program pro Mono vytváří desítky megabajtů samoúčelných softwarových závislostí na knihovnách Mono.

Předpokládá se, že v budoucnu Vala z GNOME zcela vytlačí C#/Mono.

Vala software

Projekt 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:

  • Cheese – aplikace pro používání webkamery, transformace snímaného videa v reálném čase
  • Dconf editor
  • Dova
  • Déjà Dup – nástroj pro zálohování

Ve Vale je napsána také LaTeXila, editor pro TeX a LaTeX.

Vývoji uživatelských aplikací ve Vale se věnuje 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 ElementaryOS 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

Vala (programovací jazyk)
Paradigmamultiparadigmatický
Vznikl v2008
AutorJamie McCracken a další
Vývojářkomunita Genie, GNOME Foundation
Typová kontrolasilné, statické
Hlavní implementaceprofily překladu glib, posix a dova
Ovlivněn jazykyVala, různá API GNOME, Python, Boo
OSurčeno pro GNOME, teoreticky multiplatformní
LicenceLGPL 2.1 a novější verze

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 Gee

Knihovna 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.

Dova

Dova 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:

  • dova-core (systém typů, regulární výrazy, náhrada za knihovnu libGee, práce se soubory, správa vláken, správa procesů…),
  • dova-canvas, dova-drawing, dova-imaging (2D grafika),
  • dova-dbus (systém komunikace D-Bus),
  • dova-http, dova-mail, dova-tls (podpora síťového přenosu),
  • dova-json, dova-xml, dova-sparql, dova-sql (serializace, ukládání a manipulace s daty),
  • dova-windowing, dova-x (X server)

Překladač Vala

Překladač Valy
Vývojářkomunita Valy, GNOME Foundation
Aktuální verze0.54.1 (21. září 2021)
Operační systémurčeno pro GNOME, teoreticky multiplatformní
Vyvíjeno vVala
Typ softwaruprogramovací jazyk a objektově orientovaný programovací jazyk
Licencesamotný LGPL 2.1+, včetně GCC GPL 2+
Webwiki.gnome.org/Projects/Vala
Některá data mohou pocházet z datové položky.

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).

  • glib – základní profil
  • posix – Profil posix se algoritmicky podobá profilu glib. Výsledný binární soubor je však staticky slinkován a nevzniká závislost na GLib a dalších sdílených knihovnách.
  • dova – Překlad probíhá pomocí frameworku Dova.

Profily posix a dova zatím neimplementují celý standard jazyka.

Reference

  1. Použití operátoru slice (resp. hranatých závorek) u řetězců kopíruje řešení Pythonu.
  2. Z hlediska licencí GNU je tento kód chápán jako strojový. Licence definují zdrojový kód jako preferovanou formu díla určenou pro jeho modifikace. Zdrojovým kódem je tedy pouze kód ve Vale. Všechny nezdrojové formy díla (včetně přeloženého kódu v jazyce C) jsou považovány za strojový kód.
  3. http://live.gnome.org/Vala/BindingsStatus
  4. BenchResults – vala-benchmarks - Results of the current completed benchs. – A collections of some simples benchmarks written in Vala. – Google Project Hosting
  5. http://live.gnome.org/Vala/Documentation#Projects_Developed_in_Vala
  6. Yorba
  7. http://elementaryos.org/
  8. vala, vala everywhere! | my blog
  9. jamiemcc: Introducing Genie – the smart programming language

Externí odkazy

This article is issued from Wikipedia. The text is licensed under Creative Commons - Attribution - Sharealike. Additional terms may apply for the media files.