Portál AbcLinuxu, 16. května 2024 20:34

Programování v jazyce Vala – úvod

1. 8. 2012 | Vratislav Podzimek
Články - Programování v jazyce Vala – úvod  

Už jste vyzkoušeli několik programovacích jazyků, ale od každého jste utekli s tím, že jste objevili nějaký nový zajímavý? Pokud ano, pak jste na tom jako já, pokud ne, určitě se i na vašem oblíbeném jazyce najde něco, co vám tak úplně nevyhovuje. Nebojte, nehodlám vám tvrdit, že mám pro vás spásu v podobě programovacího jazyka Vala, který je naprosto dokonalý. To, s dovolením, jako obyčejný smrtelník přenechám lidem vesmírným.

Rozhodně ale můžu říct, že mě jazyk Vala hodně zaujal již po přečtení prvních odstavců tutoriálu a několikrát mě u toho napadlo, že přesně takové konstrukce se mi na tom a tom jazyce, odkud si je Vala vypůjčila, hodně líbí. Pojďme se alespoň na některé podívat trochu podrobněji, ať vás trochu navnadím na nejen další programovací jazyk do sbírky. Pokud byste měli pocit, že příliš kritizuji zrovna vašeho oblíbence, nemějte obavy, žádný z jazyků užitých pro příklady nevyjde ze souboje jako vítěz. Tím bude samozřejmě Vala. Chtěl bych poděkovat autorům tutoriálu k Vale za skvělý text se spoustou příkladů, ze kterých si některé dovolím použít.

Nejdříve konstrukce zmíníme jen pro ukázku, později si ukážeme konkrétní použití v programu.
Patříte mezi ty, kolem kterých ostatní chodí s obdivem, ale přece jen kousek stranou, tedy znalce Perlu? A už jste si někdy říkali, že byste pro větší projekty a zejména UI aplikace zkusili něco jiného, ale nehodláte se vzdát některých bezkonkurenčních výhod, které Perl nabízí? Vala zvládá infixový zápis expandovaných proměnných v řetězcích, můžete tedy psát:

Vala jako Perl

@"Pro zadaneho uzivatele $input_user neznam udaje."

a pokud máte někde dříve v programu definovánu proměnnou input_user, bude její hodnota dosazena do řetězce. Vala jde dokonce v těchto konstrukcích ještě o kousek dál, ale o tom až později. Stejně jako mnoho ostatních programovacích jazyků je i Vala ve srovnání s Perlem mnohem méně benevolentní. A tak vám např. ekvivalent klasického Perlovského "výhružného idiomu"

open(FILE, "file.txt") || die ("Cannot open file file.txt, exitting.");

projde, pouze pokud návratové hodnoty metod open a die budou typu bool. Vala totiž za pravdivostní hodnoty považuje opravdu jen hodnoty typu bool a mezi žádné jiné typy vám logický operátor || dát nedovolí. Pro mě vždy byly největší zbraní Perlu regulární výrazy a ať jsem je používal v jakémkoliv jiném jazyce, vždy jsem s láskou vzpomínal na Perl a zoufal si, jaká by to byla krása zrovna tu část kódu psát v Perlu. No a odpověď Valy?

if (/^[A-Z0-9._%+-]+@[A-Z0-9.-]+\.[A-Z]{2,4}$/i.match(email))
{
   /* nejaky kod */
}

Zde se sluší dodat, že takový zápis regulárních výrazů je zatím experimentální funkcionalitou a při překladu o tom budete varováni.

Vala jako Python a C#

Pokud máte právě pocit, že jsem začal poněkud zostra, nebojte, žádná horší změť znaků už vás nečeká. Podívejme se na další pěkné možnosti, které nám Vala nabízí. Máte rádi Python a často používáte výřezy z řetězců či listů, ale někdy si říkáte, že byste přece jen interní atributy a metody své třídy chtěli chránit více než jen použitím podtržítka jako prvního znaku jejich identifikátoru? A jak se vám líbí tato kombinace?

class Example
{
    private string second_three_chars(string str, ...)
    {
        return str[3:6];
    }
}

Přiznávám, ten středník a složené závorky jsou z pohledu znalce Pythonu škaredé a naprosto zbytečné; na druhou stranu, všimli jste si parametrů? Žádný self, i když se jedná o metodu třídy. A co ty tři tečky? No přece proměnný počet parametrů ve stylu C. Další věc, která se mi na Pythonu hodně líbí, je možnost používání mnoha konstrukcí, pokud si pro svou třídu vytvoříte ty správné metody. __str__ je klasikou, jejíž ekvivalent má snad každý moderní jazyk, ale že vám vytvoření metod get a set dovolí používat výrazy jako a[4] = 5, to už tak obvyklé nebývá. Právě takové možnosti (později si ukážeme konkrétní příklady) poskytuje i Vala.

Pokud jste si nad prvními dvěma ukázkami zoufali, že sice vypadají dobře, ale určitě to bude další dynamický jazyk, který po vás sice nebude chtít typy proměnných ani návratových hodnot, ale za to vás neupozorní na některé zřejmé chyby, kdy do proměnné místo čísla budete „rvát“ řetězec znaků, doufám, že vás předchozí ukázka potěšila. Jak si mnozí z vás jistě všimli, Vala je silně typovaná. Co se však při pohledu na ukázku jistě vybavilo ještě více čtenářům je podobnost Valy s Javou případně s C#. Na podobnost s těmito „sourozenci“ se nyní podíváme, protože právě od nich si toho Vala vypůjčila opravdu hodně. Nicméně máte-li syndrom „antijavisty“ a každá sebelepší aplikace napsaná v Javě by vám připadala hrozně pomalá, i kdyby běžela rychleji než nativní C, už jen proto, že víte, že je napsaná v Javě, můžu vás uklidnit. Vala nevyužívá žádný virtuální stroj, není nijak zvlášť paměťově náročná a už vůbec ne pomalá. Později si v tomto textu vysvětlíme proč.

V čem se však s těmito milovanými i nenáviděnými sourozenci téměř dokonale shoduje, je syntaxe. Ta je na první pohled od Javy, a tedy i C#, k nerozeznání. Troufám si říct, že to bylo od tvůrců tohoto jazyka velmi moudré rozhodnutí, protože i když se může Vala někomu jevit jako poměrně upovídaná, čitelnost kódu je velmi dobrá. No a kdo zná např. téměř až „pohádkové zdrojové kódy“ v Adě, ten takovou vlastnost dokáže ocenit. Vala je vysokoúrovňový jazyk, který byl od počátku navrhován jako objektově orientovaný, takže na rozdíl např. právě od Ady používá klasickou tečkovou notaci pro volání metod objektů. Nemusíte tedy volat funkci, která jako první argument bere odkaz na objekt typu, nad kterým pracuje. Vala si však od Javy a C# vypůjčila i další užitečné konstrukce. Umožňuje používat abstraktní třídy i rozhraní a všechny třídy mají společného předka (k tomu vás sice Vala přímo nenutí, ale o tom až později). Oproti Javě však stejně jako C# nabízí možnost definovat a používat vlastnosti objektů a to, řekl bych, ideálním možným způsobem. Pokud z Javy znáte „nádhery“ typu

person.set_age(person.get_age() + 1);

pak vězte, že ve Vale by odpovídající kód vypadal následovně

person.age++;

a to při zachování jakékoliv funkcionality, která byla v případě Javy součástí metod set_age resp. get_age. Definice vlastnosti age by pak v nejjednodušším případě (což je, troufám si říct, většina) vypadala např. takto

public int age { get; set; }

Přidám ještě jednu velmi hezkou a užitečnou konstrukci. Všichni asi známe definici proměnné vypadající asi takto

HashMap<String, HashMap<String, ArrayList<Int>>> myvar = new HashMap<String, HashMap<String, ArrayList<String>>>();

A někteří z nás už si možná mnohokrát říkali, že by kompilátor/interpret mohl být natolik chytrý, že z pravé strany, kde konstruujeme objekt, zjistí, jaký je jeho typ, a nebudeme mu ho tedy muset říkat dvakrát. Vězte, že Vala (resp. její tvůrci) je natolik chytrá a stačí psát

var myvar = new HashMap<string, HashMap<string, ArrayList<string>>>()

přičemž lze tuto konstrukci použít kdekoliv, kde dokáže Vala odvodit typ proměnné, tedy např. i u zástupné proměnné ve foreach cyklu.

Pozn.: Omlouvám se, pokud jsem předchozími otevřenými srovnáními někoho z vás naštval, zároveň bych chtěl poprosit všechny, kteří by chtěli oponovat, že to či ono již v nových verzích jazyků není, případně to není vlastností jen mnou uvedených jazyků, aby své umírněné poznámky přidali ke komentářům. Stejně jako čtenáři tohoto článku se rád dozvím něco nového, ale troufám se považovat za dobrý příklad někoho, kdo se v prostředí programování v různých jazycích pohybuje dostatečně na to, aby se k němu všeobecně známé novinky dostaly poměrně brzy.

Další vlastnosti

Na závěr popisu dobrých vlastností Valy se ještě podívejme na některé další, které prozatím jen zmíníme. Všechny řetězce ve Vale jsou implicitně v kódování UTF-8 a nemusíte si tedy lámat hlavu s problematikou různých národních abeced. Jak již bylo vidět z příkladů, můžeme používat tzv. generické datové typy (kontejnery), do kterých lze ukládat objekty různých typů. Nemusíme se bát ani vláken, protože i pro ně Vala poskytuje dobré nástroje, jež značně usnadňují práci. Co se týče efektivního využívání zdrojů, máme ještě jednu možnost – asynchronní volání. Tedy zatímco metoda čeká na data z disku, může již své volající proceduře vrátit alespoň jejich část, která může být zpracována a např. zobrazena. Než je toto provedeno, má již volaná procedura opět připravená data z disku, která může poskytnout.

Další velmi užitečnou možností je snadné psaní aplikací poskytujících nebo využívajících služby na sběrnici DBus, stačí kód dobře „oanotovat“. No a co potřebuje aplikace, má-li poskytovat nějaké asynchronně používané služby? Přece hlavní smyčku, kterou lze ve Vale vytvořit velmi snadno. Vše, co jsem doposud zmínil, známe i z jiných běžně používaných jazyků. Co však pro mě bylo v případě Valy novinkou, byla implicitní kontrola parametrů, jestli nejsou rovny hodnotě null. Samozřejmě toto chování může být někdy více na škodu než k užitku, a tak již prosté přidání otazníku k typu (tedy např. string?) tuto kontrolu vypíná. Existují i další metody, ale o těch až někdy příště. Další pro mě novou věcí byla přímo jazykem poskytovaná možnost zápisu vstupních a výstupních podmínek metod. Zde si přece jen dovolím krátkou ukázku

public int rectangle_volume(int a, int b)
   requires (a >= 0 && b >= 0)
   ensures (result > 0 && (result == a * b))
{
   return a * b;
}

kde result je speciální identifikátor zastupující návratovou hodnotu.

Pod pokličkou

Nyní se pojďme Vale společně podívat trochu „pod pokličku“. Až doteď jsem totiž před vámi tajil tu možná nejdůležitější věc. Zhluboka se nadechněte... Zdrojový kód ve Vale je totiž se všemi těmi krásnými vysokoúrovňovými konstrukcemi nejdříve přeložen do C se značným využitím GObject a GLib a teprve až tento „mezikód“ je přeložen do binární podoby spustitelné na tom či onom operačním systému. Z toho vyplývá mnoho pozitivních i negativní důsledků. Příkladem pozitivních je jistě rychlost běhu programů (pro ukázku viz Vala Benchmarking), které je dosaženo překladem do binární podoby navíc s využitím již dlouhou dobu zkoumaných optimalizací pro jazyk C.

Absence mezilehlé vrstvy v podobě interpretu nebo virtuálního stroje s sebou však kromě pozitivního vlivu na rychlost přináší i negativum v podobě nepřenositelnosti binární podoby programu. Máte-li zdrojové kódy, pak máte samozřejmě na přenositelnost mnohem lepší šance, protože GLib i GObject jsou k dispozici pro mnoho platforem. Velkou výhodou a dokonce i jedním z důvodů pro  vytvoření Valy je možnost psaní vysokoúrovňových knihoven využitelných v mnoha programovacích jazycích. Ať už je to Python, Perl, Java nebo třeba Haskell, využití „Cčkových“ knihoven je ve všech těchto jazycích relativně snadné. V případě využití GObject introspekce, která je ze zdrojových kódů ve Vale velmi dobře generovatelná, např. v Pythonu ani nemusíte poznat, že najednou používáte zkompilovanou knihovnu původně napsanou v úplně jiném jazyce.

Dost už bylo povídání. Programovací jazyky jsou tu přece od něčeho úplně jiného, než od toho, aby se o nich povídalo a byly vzájemně srovnávány. Zkusíme si napsat náš první program ve Vale, zkompilovat ho a spustit. Zároveň si tak ukážeme, jak vypadá vygenerovaný mezikód v C. Všechny zdrojové kódy k tomuto seriálu o programování ve Vale budou postupně v git repozitáři na GitHubu. Aby se v repozitáři lépe orientovalo, budu pro každý díl tohoto seriálu dělat tag. Ještě jedna poznámka ke zdrojovým kódům – protože by se mohlo stát, že by je chtěl použít někdo jiný, omezím se na angličtinu, a to nejen v případě identifikátorů, ale i komentářů. I když do budoucna budou v textu jen ty nejdůležitější fragmenty zdrojových kódů, pro tentokrát si ukážeme kompletní program

/* file compile_test.vala */

//define our namespace
namespace compile_test
{

    /**
     * Example class showing Vala syntax and serving as a compile test.
     *
     * This class named CompileTest is inherited from the Object from GLib.
     */
    class CompileTest : GLib.Object
    {
        /**
         * The main method that is invoked when this program is run.
         *
         * @param args command line arguments
         */
        public static int main(string[] args)
        {
            //call method printf of the object stdout (standard output)
            stdout.printf("I have been successfully compiled and run.\n");
            return 0;
        }
    }

}

Nyní si tento program zkusíme zkompilovat a spustit. Budeme k tomu, překvapivě, potřebovat kompilátor – program valac. Ten byste ve většině distribucí měli najít v balíku s prostým názvem vala. Věřím, že teď už nikoho nepřekvapí, že následujícím krokem bude příkaz valac compile_test.vala, čímž dostaneme binární program. Protože si však chceme ukázat i „Cčkový“ mezikód, spustíme kompilátor ještě jednou, tentokrát s přepínačem -C. Vznikne tak soubor compile_test.c. Zkuste si jej otevřít a prohlédnout, věřím, že znalým GLib a GObject bude kód připadat dobře čitelný, všem ostatním snad alespoň ukáže jak jednoduchý je kód ve Vale ve srovnání s jeho ekvivalentem v nativním C.

Pokud máte rádi editor Vim, musím vás bohužel zklamat. Protože je Vala poměrně nový jazyk, tento editor si neporadí se zvýrazňováním syntaxe. Tedy dokud si s ním trochu nepohrajete. Pro Emacs bývá „zabalíkováno“ rozšíření emacs-vala a pokud budete mít štěstí a program Vala IDE zrovna nebude padat jako sníh, můžete použít dokonce editor vytvořený speciálně pro tento jazyk. Na závěr bych vám ještě doporučil otevřít, prohlédnout a zkompilovat soubor features.vala, který na poněkud umělých příkladech demonstruje některé z výše uvedených vlastností jazyka Vala. Snažil jsem se do něj umístit dostatek komentářů, aby nebylo třeba žádné další vysvětlování, ale pokud by se přece jen něco našlo, prosím o přidání komentáře pod článek. Pokusím se co nejdříve odpovědět.

Závěr

A to je tedy pro tentokrát vše. Doufám, že se mi ve vás podařilo projevit zájem o tento moderní programovací jazyk a rádi se se mnou v příštích dílech tohoto seriálu (příp. dalších článcích) podíváte na příklady jeho použití. Příště již začneme vytvářet opravdovou aplikaci, kterou budeme postupně rozšiřovat a zdokonalovat. Společně si tak ukážeme další konstrukce programovacího jazyka Vala, ale především použití různých knihoven.

Seriál Programování v jazyce Vala (dílů: 3)

První díl: Programování v jazyce Vala – úvod, poslední díl: Ze 4 s na 0,9 s – programovací jazyk Vala v praxi.
Následující díl: Programování v jazyce Vala - základní prvky jazyka

Další články z této rubriky

LLVM a Clang – více než dobrá náhrada za GCC
Ze 4 s na 0,9 s – programovací jazyk Vala v praxi
Reverzujeme ovladače pro USB HID zařízení
Linux: systémové volání splice()
Programování v jazyce Vala - základní prvky jazyka

ISSN 1214-1267, (c) 1999-2007 Stickfish s.r.o.