abclinuxu.cz AbcLinuxu.cz itbiz.cz ITBiz.cz HDmag.cz HDmag.cz abcprace.cz AbcPráce.cz
AbcLinuxu hledá autory!
Inzerujte na AbcPráce.cz od 950 Kč
Rozšířené hledání
×

dnes 12:33 | Zajímavý software

Článek ne Medium představuje nejnovější stabilní verzi 2.0 svobodné decentralizované mikroblogovací platformy a sociální sítě podobné Twitteru Mastodon (Wikipedie). Detailní přehled novinek na GitHubu [Hacker News].

Ladislav Hagara | Komentářů: 0
dnes 06:00 | Komunita

V Praze na půdě Elektrotechnické fakulty ČVUT dnes probíhá RT-Summit 2017 – setkání vývojářů linuxového jádra a uživatelů jeho real-time verze označované jako preempt-rt. Přednášky lze sledovat online na YouTube.

Ladislav Hagara | Komentářů: 0
včera 14:33 | Zajímavý projekt

Blender Animation Studio zveřejnilo první epizodu z připravovaného animovaného seriálu The Daily Dweebs o domácím mazlíčkovi jménem Dixey. Ke zhlédnutí také ve 3D s rozlišením 8K.

Ladislav Hagara | Komentářů: 0
včera 12:34 | Komunita

Aktualizovanou počítačovou hru Warhammer 40,000: Dawn of War III v ceně 39,99 eur běžící také na Linuxu lze o víkendu na Steamu hrát zdarma a případně ještě v pondělí koupit s 50% slevou. Do soboty 19:00 lze na Humble Bundle získat zdarma Steam klíč k počítačové hře Sid Meier's Civilization® III v ceně 4,99 eur běžící také ve Wine.

Ladislav Hagara | Komentářů: 0
včera 00:22 | Nasazení Linuxu

Společnost Samsung oznámila, že skrze dokovací stanici DeX a aplikaci Linux on Galaxy bude možno na Samsung Galaxy S8 a S8+ a Galaxy Note 8 provozovat Linux. Distribuce nebyly blíže upřesněny.

Phantom Alien | Komentářů: 19
19.10. 23:55 | Komunita

Společnost Purism na svém blogu oznámila, že její notebooky Librem jsou nově dodávány se zrušeným (neutralized and disabled) Intel Management Engine (ME). Aktualizací corebootu na již prodaných noteboocích lze Management Engine také zrušit. Více v podrobném článku.

Ladislav Hagara | Komentářů: 0
19.10. 21:44 | Nová verze

Organizace Apache Software Foundation (ASF) na svém blogu slaví páté výročí kancelářského balíku Apache OpenOffice jako jejího Top-Level projektu. Při této příležitosti byl vydán Apache OpenOffice 4.1.4 (AOO 4.1.4). Podrobnosti v poznámkách k vydání. Dlouhé čekání na novou verzi tak skončilo.

Ladislav Hagara | Komentářů: 6
19.10. 19:22 | Pozvánky

Již příští týden - 26. a 27. října se v Praze v hotelu Olšanka odehraje OpenWRT Summit. Na webu konference naleznete program a možnost zakoupení lístků - ty stojí 55 dolarů. Čtvrtek bude přednáškový a v pátek se budou odehrávat převážně workshopy a meetingy.

Miška | Komentářů: 1
19.10. 13:44 | Nová verze

Bylo vydáno Ubuntu 17.10 s kódovým názvem Artful Aardvark. Ke stažení jsou Ubuntu Desktop a Server, Ubuntu Cloud Images, Ubuntu Netboot, Kubuntu, Lubuntu a Lubuntu Alternate, Lubuntu Next, Ubuntu Budgie, Ubuntu Kylin, Ubuntu MATE, Ubuntu Studio a Xubuntu. Podrobnosti v poznámkách k vydání.

Ladislav Hagara | Komentářů: 23
19.10. 13:00 | Komunita

MojeFedora.cz informuje, že Fedora 27 dostane podporu pro AAC. Podpora multimediálních formátů je ve výchozí instalaci Fedory tradičně limitovaná kvůli softwarovým patentům, ale desktopový tým Red Hatu se ji i tak snaží v poslední době co nejvíce rozšířit. Už nějaký čas obsahuje kodeky pro MP3, H.264, AC3 a nyní byl přidán také kodek pro další velmi rozšířený zvukový formát – AAC.

Ladislav Hagara | Komentářů: 2
Jak se vás potenciálně dotkne trend odstraňování analogového audio konektoru typu 3,5mm jack z „chytrých telefonů“?
 (10%)
 (1%)
 (1%)
 (1%)
 (75%)
 (13%)
Celkem 167 hlasů
 Komentářů: 7, poslední 19.10. 23:06
    Rozcestník

    Programování v jazyce Vala - základní prvky jazyka

    4. 9. 2012 | Vratislav Podzimek | Programování | 4191×

    V minulém díle tohoto „měsíčníku“ (omlouvám se, ale dříve jsem další článek napsat nestihl) jsme si ukázali některé zajímavé vlastnosti programovacího jazyka Vala spolu s krátkými vzájemně nesouvisejícími ukázkami kódu. O tom, jaký ve skutečnosti programovací jazyk je, ale jistě nejlépe napoví, když jej člověk vidí „v akci“, tedy jako zdrojový kód programu, který k něčemu slouží.

    Protože jsou však většinou zdrojové kódy běžně užívaných programů velmi dlouhé a komplikované, rozhodl jsem se, že bude pro tento seriál nejvhodnější začít psát jednoduchou aplikaci od prvních řádků kódu, který se zde budu snažit dostatečně komentovat. Samozřejmě především aspekty specifické pro Valu, nikoliv aspekty programování jako takového. Předem upozorňuji, že zdrojový kód bude reflektovat fakt, že je naše aplikace psána pro účely tohoto seriálu. Věřím, že se tak vyhneme zdlouhavým diskuzím o tom, jak by se dal kód změnit, aby byl kratší, používal méně proměnných, běžel o mikrosekundu rychleji apod. Ale dost už bylo řečí kolem, pusťme se do programování.

    Obsah

    Základní idea

    link

    Nejdříve si představme základní ideu naší aplikace, abychom věděli, k čemu budeme směřovat. Bude se jednat o jednoduchý nástroj na správu úkolů, který bude umožňovat přidávání a odebírání úkolů, jejich shromažďování do kolekcí a označování za (ne)hotové. Jako pracovní název jsem zvolil DoNotForget, ale rovnou bych rád upozornil, že bych se chtěl vyhnout používání zkratky DNF, protože to je zkratka, doufejme podstatně úspěšnějšího a důležitějšího, projektu Aleše Kozumplíka. Postupně budeme aplikaci rozšiřovat a zdokonalovat, vyvineme různá uživatelská rozhraní, různé způsoby ukládání dat v paměti i na disk a podle zájmu o pokračování seriálu i různá další rozšíření tak, abychom si ukázali funkcionalitu knihoven pro obvyklé činnosti moderní aplikace (např. komunikaci přes DBus nebo získávání dat z webu). V git repozitáři pro kód spojený s těmito články jsem vytvořil samostatný adresář s názvem do_not_forget a příslušným Makefile pro snadnější práci.

    Protože si Vala nejlépe rozumí s objekty a protože je objektový návrh přirozenější a v dnešní době častěji používaný, i naši aplikaci si rozdělíme na několik samostatných tříd objektů řešících různé úlohy. No a protože má DoNotForget umožňovat správu úkolů, přirozeným začátkem psaní kódu bude třída reprezentující úkol (Task). Pojďme se tedy podívat na její implementaci a vlastnosti Valy, které využívá.

    namespace Tasks {
    
        /**
           Basic class for tasks allowing storing task's description and state.
        */
        class Task : GLib.Object {
    
            /* Private attributes */
            protected string desc;
    
            protected bool _done;
    
            /* Constructors */
            public Task (string desc) {
                this.desc = desc;
                this.done = false;
            }
    
            public Task.with_state (string desc, bool done) {
                this.desc = desc;
                this._done = done;
            }
    
            /* Properties */
            public string description {
                get { return desc; }
                set { desc = value; }
            }
    
            public virtual bool done {
                get { return _done; }
                set { _done = value; }
            }
    
            /* standard to_string() method that enables the @"$obj" functionality */
            public virtual string to_string() {
                var done_str = _done ? "done" : "not done";
    
                return @"$desc ($done_str)";
            }
    
        }
    }
    

    Na prvním řádku definujeme samostatný jmenný prostor pro třídy úkolů a to ze dvou důvodů. Tradiční důvod je pro zamezení kolizí jmen, ten druhý, a pro mě v případě tak malého projektu snad ještě důležitější, je to, že následným používáním using Tasks; na začátku zdrojových kódů využívajících třídy úkolů zdůrazníme, odkud tyto třídy a metody bereme. Kompilátor Valy totiž, na rozdíl např. od Ady, ale podobně jako C nebo C++, neumí při kompilaci zahrnout závislosti a musíme kompilátoru přímo vyjmenovat soubory, ve kterých jsou všechny elementy využívané v naší aplikaci nebo knihovně. Právě z tohoto důvodu považuji za velmi vhodné, když jde na začátku zdrojového souboru vidět (byť nepřímo), odkud se berou mnohé třídy, metody apod. a které soubory je tedy nutné zahrnout do kompilace. I v případě použití samostatného jmenného prostoru bychom mohli using Tasks; vynechat, ale přišli bychom o tuto nápovědu a při používání prvků z toho jmenného prostoru bychom museli psát prefix „Tasks.“.

    Nikoho asi nepřekvapí, že dále definujeme třídu Task, která dědí od třídy GLib.Object. Zde si dovolím dvě krátké poznámky – prefix „GLib.“ bychom mohli vynechat, neboť Vala v každém zdrojovém souboru implicitně používá jmenný prostor GLib, nicméně já používám plný název pro zdůraznění, odkud třída Object pochází; neplatí však, že by implicitně i každá třída dědila od třídy GLib.Object podobně, jako to známe např. z Pythonu, ale zároveň bychom neodvozením našich tříd od GLib.Object přišli o některé možnosti. Podrobnosti s dovolením nechám na laskavém čtenáři, věřím, že si vystačíme s poučením, že je doporučováno dědit vlastní třídy od GLib.Object.

    U definice atributů asi nepřekvapí nic, snad jen podtržítko v identifikátoru _done, jež je zde použito, aby přirozenější identifikátor done zůstal k dispozici pro veřejně přístupnou vlastnost. Třída Task má definovány dva konstruktory. Vala sice neumožňuje přetěžování metod, takže nemůžeme definovat dva konstruktory pojmenované názvem třídy s různým počtem nebo typy parametrů, ale ve stylu GObject můžeme definovat konstruktory s různými „přídomky“ napovídajícími, jaké parametry očekávají. Dále definujeme dvě vlastnosti, z nichž druhá je označena modifikátorem virtual. Znalým C++ asi není třeba nic vysvětlovat, pro ostatní raději uvádím, že kombinace modifikátorů virtual(u metody předka) a override(u metody potomka) umožňuje polymorfismus.

    Klasikou je i použití this pro odkazování se na data instance (i když Vala při překladu do C používá self). to_string je metoda se syntaktickou podporou a její definování zpřístupní infixový zápis proměnných v řetězcích – např. @„ukol: $task“, kde task je instance třídy Task. Metoda využívá klasický ternární operátor známý z jiných programovacích jazyků. Dále je ve zdrojovém kódu definována odvozená třída LongTimeTask určená pro úkoly s delší dobou trvání, u nichž chceme sledovat postup (v procentech). Z hlediska Valy je na této třídě zajímavé jen to, že používá klíčové slovo base pro volání konstruktoru předka (což je vyžadováno) a metody to_string předka. Použití těchto dvou tříd ukazuje test, který provádí základní operace. Jedinou věcí, která by zde mohla překvapit, je klíčové slovo is, jež slouží pro testování typu instance za běhu.

    Kolekce úkolů

    link

    Už tedy umíme uložit informace o jednotlivých úkolech. Chybí nám ale možnost pracovat se skupinami úkolů. Napravíme to tedy třídou, která bude reprezentovat kolekci úkolů, a na její implementaci si ukážeme možnosti pro práci se skupinami objektů. Pro ty z nás, jež s programováním nezačali u „javovských“ kolekcí ani STL knihovny C++, je asi přirozeným základním způsobem pro práci se skupinou objektů použití pole. Stejně přirozené je však očekávat, že nám moderní programovací jazyk nabídne jiné, z hlediska programátora praktičtější, možnosti. Proto rovnou vytvoříme rozhraní, které bude muset každá kolekce úkolů implementovat. Získáme tak možnost jednoduše zaměňovat používání jedné třídy třídou druhou. Na způsobu definování rozhraní ve Vale asi nic nepřekvapí..., nebo ano?

    interface TaskCollection : GLib.Object {
    
        /* Methods for adding and removing tasks */
        public abstract void add_task (Task task) throws TaskCollectionError;
        public abstract void remove_task (Task task);
    
        /* Method making the indexing syntax for getting items work */
        public abstract Task? get (int index);
    
        /* Method making the 'in' operator work */
        public abstract bool contains (Task task);
    
        /**
           Method making the iteration work.
           Vala's interfaces can be used as mixins, so this method is not
           abstract and have its implementation in the interface code.
        */
        public TasksIterator iterator () {
    	return new TasksIterator (this);
        }   
    
        /* Properties */
        public abstract string title {
    	get;
    	set;
        }
    
        public abstract int number_of_tasks {
    	get;
        }
    
        /* for debugging */
        public abstract string dump {
    	owned get;
        }
    
    }
    

    Přece jen se nějaké nezvyklosti v kódu nebo jeho významu objevují, a tak si je opět jednu po druhé projděme. Dovolím si přeskočit komentář, proč zrovna takové názvy metod a proč zrovna tyto metody, o tom doufám dostatečně vypovídají komentáře přímo v kódu. Nicméně hned první řádek, i když se zdá „neškodný“ skrývá jednu malou záludnost. Možná si říkáte: „Rozhraní zděděné z klasické neabstraktní třídy? Co to?“. Prozradím vám, že význam : GLib.Object je zde trochu jiný. Jedná se totiž o tzv. prerekvizitu, kterou musí splňovat každá třída, která o sobě chce „prohlašovat“, že implementuje námi definované rozhraní. Asi nikoho nepřekvapí, že těchto prerekvizit může být u definice rozhraní uvedeno více. Mohou tam být jiná rozhraní, případně třídy, jejichž potomky musí být třídy implementující rozhraní. Mnohonásobnou dědičnost však Vala nepodporuje (tedy pokud „nedědíme“ rozhraní, kde se nejedná o dědičnost).

    I další řádky vypadají trochu podivně, nemyslíte? Deklarování metod v  rozhraní jako abstraktních? Také máte pocit, že by to snad Vala mohla odhadnout z toho, že jsou v definici rozhraní? Mohla, ale je třeba kompilátoru říct, které metody si může implementující třída dovolit přímo používat. Rozhraní ve Vale totiž nejsou jen rozhraní v tradičním významu tohoto slova v objektovém programování, ale tzv. mixiny, což nám dává možnost omezené mnohonásobné dědičnosti. Vedle rozhraní Vala zná i abstraktní třídy (modifikátor abstract) s (volitelně) abstraktními metodami. S deklarací první požadované metody bychom se rovnou měli vrhnout i na výjimky, ale to si, myslím, můžeme nechat na později.

    Co znamená otazník u typu, to jsme si již vysvětlili v minulém článku. Tak jen pro zopakování – otazník říká, že se na místě jako hodnota může objevit i null. Na příkladu metody iterator vidíme, že můžeme využít rozhraní i pro definici metody, abychom nemuseli stejný kód opakovat v každé třídě, která rozhraní implementuje. Poslední zajímavostí, než se dostaneme k výjimkám a třídě TaskIterator, je modifikátor owned u definice get části vlastnosti dump. Vala totiž implicitně u vlastností vrací tzv. „unowned“ (nevlastněné) objekty, což jsou, ve zkratce řečeno, jen odkazy na objekty, které nezvyšují počítadlo odkazů daných objektů. Trochu srozumitelnější možná bude, když se zamyslíme nad významy slov „owned“ (vlastněný) a „unowned“ (nevlastněný). Pokud vrátíme objekt jako nevlastněný, znamená to, že volajícího nepřidáváme jako vlastníka objektu, a tudíž naznačujeme, že o (ne)existenci takového objektu rozhodujeme pouze my (což je na místě zejména právě u vlastností, protože jejich hodnoty jsou velmi často odkazy na interní atributy objektů, u kterých nechceme, aby zůstávaly v paměti po dealokaci objektu samotného).

    Protože však v našem případě collection.dump vrací nově zkonstruovaný řetězec (který na rozdíl např. od typu int není jednoduchým typem, ale objektem) vytvořený v těle get části, musíme jej vracet jako owned, abychom předali vlastnictví (my o něj totiž přijdeme na konci těla get části, kdy se sníží počítadla odkazů u lokálních proměnných a dojde k případné dealokaci).

    Výjimky

    link

    Konečně se tak dostáváme k výjimkám a třídě TaskIterator. Začněme výjimkami. V úvodu zdrojového kódu našich kolekcí úkolů je tato část:

    public errordomain TaskCollectionError {
        MAX_TASKS_LIMIT_EXCEEDED,
    }
    

    Vala pro výjimky interně využívá metody dostupné v GLib – GError. Protože však tento systém funguje poněkud jinak než např. výjimky v Javě, měl by být využíván opravdu jen pro chyby vzniklé za běhu, které nelze předem vyloučit a ze kterých je možné se „vzpamatovat“. Pro ostatní případy jsou určené různé testy na omezení představené v předchozím dílu seriálu. Pokud však chceme používat výjimky, měli bychom si definovat chybovou doménu, tedy v podstatě jakousi kategorii chyb. V této kategorii poté můžeme definovat jednotlivé typy chyb. Zachytávat však lze výjimky jen podle kategorie. Až pozdějším testem pomocí klíčového slova is můžeme zjistit, jakého typu je zachycená výjimka. Použití metody, která může „vyhodit výjimku“, pak vypadá např. následovně:

    try {
        collection.add_task (task1);
    }   
    catch (TaskCollectionError e) {
        stdout.printf (@"Failed to add task '$task1': %s\n", e.message);
        if (e is TaskCollectionError.MAX_TASKS_LIMIT_EXCEEDED) {
             stdout.printf ("Cannot add more tasks!");
        }
    }
    

    Iterátory

    link

    Dále je v kódu definována třída TaskIterator, která slouží pro iteraci přes kolekci úkolů, zejména pomocí foreach-cyklu. Abychom mohli přes objekt nějakého typu T iterovat pomocí foreach-cyklu, musí mít buď

    • metodu T get (T1 index) a vlastnost T1 size { get; }, nebo
    • metodu s názvem iterator, která vrací objekt, jenž má buď metody bool next a T get pro testování existence další položky a její získávání, nebo metodu T? next_value, která v případě neexistence další položky vrací null.

    Protože máme definováno rozhraní, které musí každá kolekce úkolů implementovat, můžeme definovat obecný iterátor pro všechny naše kolekce. Implementace je samozřejmě k nahlédnutí, testování i různým úpravám na GitHubu.

    Pole

    link

    Už tedy víme, jaké veřejné metody má naše kolekce úkolů mít, a tedy i to, k čemu ji bude možno používat. Co se týče vlastní implementace vnitřních mechanismů, tak ta samozřejmě rozhraním omezena není. Jak už jsem si troufl odhadnout výše, základním a nejpřirozenějším principem, jak ukládat skupinu objektů nebo údajů, je pravděpodobně pole. Vala samozřejmě práci s poli nabízí a přidává i některé praktické mechanismy, které tuto práci usnadňují. Pojďme ale pěkně od začátku. Naše první třída implementující rozhraní kolekce úkolů bude využívat pole o statické velikosti, kde bude položky ukládat jednu po druhé. To samozřejmě přináší několik problémů v podobě plýtvání s pamětí, omezení maximálního počtu položek, přeskládávání položek při smazání atd. To nám však pro ukázku práce s poli nijak nevadí, a proto se podívejme, jak takový kód využívající pole o statické velikosti vypadá. Nejdříve musíme pole deklarovat a vytvořit:

    private static const int MAX_TASKS = 100;
    
    private Task[] tasks_array = new Task[MAX_TASKS];
    

    Tento zápis se, nemýlím-li se, nijak neliší od zápisu v Javě nebo C#, zkrátka definujeme pole o velikosti dané konstantou MAX_TASKS. Problémem ale je, že budeme muset hlídat, kde se v poli nachází poslední vložený úkol a kontrolovat, abychom při vkládání nepřesáhli velikost pole. K tomu nám poslouží soukromý atribut private int tasks_top = -1 inicializovaný na hodnotu -1. Tento atribut se používá jako horní mez při procházení pole, zvýšený o jedničku dává počet položek v poli a umožňuje nám vkládat úkoly na nové pozice dále v poli tak, abychom nepřepisovali ty vložené dříve. Musíme jej však samozřejmě správně inkrementovat a dekrementovat při přidávání resp. odebírání položek. Jedinou metodou, kterou si z definice této třídy kolekcí ukážeme, bude právě metoda pro odebírání úkolu, ostatní jsou triviální. Kompletní implementace třídy je samozřejmě k dispozici na GitHubu.

    public void remove_task (Task task) {
        int i = -1;
        bool found = false;
    
        /* find the task or go through the whole array */
        while ((i <= tasks_top) & !found) {
    	i++;
    	found = tasks_array[i] == task;
        }
    
        /* if task not found, just return (nothing to do) */
        if (!found) {
    	return;
        }
    
        /* else remove the task (replace by null) */
        tasks_array[i] = null;
    
        /* and move the rest of the tasks to left */
        for (var j = i; j < tasks_top; j++) {
    	tasks_array[j] = tasks_array[j+1];
        }
    
        /* finally, decrease the tasks_top value */
        tasks_top--;
    }
    

    Jak již určitě všichni pochopili, metoda funguje tak, že se pokusí najít daný úkol v interním poli; pokud jej nenajde, skončí, pokud jej najde, odstraní ho z pole přepsáním hodnoty na null a posunutím zbývajících položek s vyššími indexy o jednu pozici směrem k začátku, abychom zaplnili mezeru po tomto úkolu. Věřím, že všechny syntaktické prvky jsou známy a nepotřebují žádný zvláštní komentář. V rámci této třídy se ještě podívejme na metodu get:

    public new Task? get (int index)·
        requires (index <= tasks_top)
    {
        if (index > tasks_top)
    	return null;
        else
    	return tasks_array[index];
    }
    

    Zajímavé jsou první dva řádky. Klíčové slovo new říká, že toto je nová metoda get, nikoliv nová implementace metody předka, tedy GLib.Object.get. Klíčové slovo new způsobí zamaskování metody předka touto novou metodou; pokud bychom jej vynechali, překladač by nás varoval, že tuto metodu má i předek. Typ s otazníkem a použití omezujících podmínek jsme si vysvětlili již v minulém díle seriálu. Zde si však dovolím malé upozornění – při použití omezujících podmínek v kombinaci s dědičností jsem narazil na chybu, kdy přeložený program nefungoval správně. Později přidám do komentářů odkaz na bugreport, kdyby měl někdo zájem o bližší informace.

    Dynamická pole

    link

    Chceme se ale zabývat především využíváním polí, a proto se pojďme podívat, co dalšího Vala nabízí. Další třída implementující rozhraní kolekce úkolů používá jako interní strukturu pro ukládání dat pole s dynamickou velikostí, které je automaticky zvětšováno v případě potřeby. Zvětšování probíhá tradičním způsobem, tedy vždy na dvojnásobek původní velikosti. Dynamicky zvětšované pole deklarujeme jako:

    private Task[] tasks_array = {};
    

    Protože má se však pole dynamicky zvětšuje, nemáme kontrolu nad jeho velikostí. Ta by nás sice nemusela zajímat, ale opět bychom si museli udržovat počet úkolů v kolekci v nějakém atributu. Pole ve Vale mají však pro podobné účely vlastnost length, která, jak název napovídá, vrací délku pole. U pole se statickou velikostí je to velikost pole zadaná při jeho vytvoření (nebo zvětšení – viz dále), u dynamicky se zvětšujícího pole je to aktuální počet položek v poli. Naše nová kolekce úkolů s dynamickým polem tedy nemá žádný atribut tasks_top, ale využívá přímo tasks_array.length s případnou úpravou o -1. Do dynamicky se zvětšujícího pole přidáváme položky pomocí operátoru +=, což ukazuje např. metoda add_task:

    public void add_task (Task task) {
        tasks_array += task;
    }
    

    Operátor -= však prvky neodebírá, a proto metoda remove_task vypadá téměř stejně jako v případě kolekce se statickým polem jen s tím rozdílem, že používá tasks_array.length místo atributu tasks_top. V závěru metody pak provádíme dekrementaci tasks_array.length, aby následující vložení nové položky proběhlo dle očekávání. Doporučuji si prohlédnout plný zdrojový kód tříd kolekcí úkolů spolu se zdrojovým kódem jejich testů.

    Na závěr této podčásti o polích se sluší dodat pár poznámek, pro které se mi nepodařilo vymyslet rozumnou ukázku v kódu. U polí můžeme používat výřezy (pole[1:3]) a samozřejmě můžeme klasickým způsobem definovat vícerozměrná pole (int[,] 2Dpole = new int[4,5];). V případě vícerozměrných polí se z vlastnosti length stává pole hodnot, určující délku jednotlivých dimenzí (v našem případě 2Dpole.length[0] == 4 a 2Dpole.length[1] == 5). Vala nám však neumožní přístup k jednotlivým „řádkům“ pole (de facto vektorům matice), výraz 2Dpole[0] je neplatný a neprojde přes kompilátor a stejně tak i pokus o vytvoření výřezu (slice) z vícerozměrného pole. Výřez z jednorozměrného pole není problém, výsledkem je nové pole o odpovídající velikosti.

    Pokud při vytváření pole zadáme do hranatých závorek velikost a vynecháme část od '=' dále (int f[10];), dostaneme pole s fixní velikostí alokované na zásobníku. Ostatní druhy polí můžeme zvětšovat příp. zmenšovat použitím jejich metody resize (např. pole.resize(10)) s tím, že při zmenšování jsou zachována pouze data, která byla na indexech nižších, než je nová velikost. Poslední poznámkou budiž upozornění, že Vala nedělá žádnou kontrolu při přistupování k položkám pole, a tak se snadno dostaneme k „oblíbenému“ zásahu jádra operačního systému v podobě „Segmentation fault“.

    Kolekce kolekcí

    link

    V aplikaci DoNotForget budeme chtít spravovat více kolekcí úkolů. Mohli bychom tedy vytvořit třídu pro kolekci kolekcí a možná i pokračovat v podobném duchu. Uděláme to ale jinak, vytvoříme třídu TaskManager, která bude umožňovat správu kolekcí a s níž později bude komunikovat uživatelské rozhraní aplikace. A protože chceme zabránit inkonzistenci dat, kdy by různé části aplikace používaly různé manažery a vkládaly tak úkoly nebo celé kolekce na různá místa, uděláme za třídy TaskManager tzv. singleton. Vytvoříme třídní atribut (K. Marx by měl radost) udržující jedinou existující instanci třídy, soukromý konstruktor a veřejnou metodu, která naši jedinou instanci vrátí. Vše nám zařídí následující kód:

    /** 
        Class for a singleton object, that manages task collections.
    */
    class TaskManager : GLib.Object {
    
        private static TaskManager instance;
    
        private HashMap<string, TaskCollection> _collections;
    
        public static TaskManager get_instance () {
    	instance = instance ?? new TaskManager (); 
    	return instance;
        }   
    
        private TaskManager () {
    	_collections = new HashMap<string, TaskCollection> (); 
        }
    

    Operátor ?? nám ze dvou výrazů vybere ten, který je různý od  null, případně ten druhý. instance ?? new TaskManager (); je tedy ekvivalentní výrazu a != null ? a : b;. Privátní atribut _collections využívá generický typ HashMap z knihovny Gee. Proto to musíme při kompilaci kompilátoru říct pomocí přepínače --pkg, konkrétně --pkg=gee-1.0, který přidáme do našeho Makefile. Podrobněji se na tuto knihovnu i její využití podíváme v příštím díle, prozatím si doufám vystačíme s vysvětlením, že TaskManager využívá mapu, která mapuje názvy kolekcí na kolekce samotné. Ve zbývající části zdrojového kódu této třídy není z  hlediska programovacího jazyka nic zajímavého ani nového.

    Pomocné funkce

    link

    Konečně máme „zázemí“ připraveno a můžeme se pustit do psaní aplikace DoNotForget a jejího uživatelského rozhraní. Začneme tím nejjednodušším, tedy rozhraním využívajícím příkazový řádek (CLI). A protože očekáváme, že budeme mít různá uživatelská rozhraní, začneme vytvořením jednoduchého rozhraní programového, jež bude muset každé uživatelské rozhraní implementovat. Požadujeme jen, aby bylo možné instanci rozhraní nastavit manažer úkolů a zjistit, jaký manažer úkolů má nastaven (vím, že vzhledem k tomu, že je TaskManager singleton, je tato vlastnost zbytečná, ale bývá zvykem definovat privátní atributy a k nim veřejné vlastnosti) a aby mělo rozhraní metodu run, která po inicializaci aplikace a manažera umožní spuštění rozhraní. Protože začínáme s rozhraním využívajícím příkazový řádek, pomůžeme si malou „knihovničkou“ s několika funkcemi, jejichž krátký kód bychom jinak opakovali pořád dokola. Začneme tou úplně nejjednodušší, jednořádkovou:

    void println (string text = "") {
        stdout.printf (@"$text\n");
    }
    

    Tato funkce se možná může zdát úplně zbytečná, ale ušetří hodně psaní a zpřehlední ta místa v kódu, kde se odehrává hodně výpisů na standardní výstup. Abychom si usnadnili vypisování prázdného řádku (vytvoření vertikální mezery), používáme parametr s výchozí hodnotou. Následně je možné tuto funkci (nebo proceduru, chcete-li) volat buď jako println (msg);, nebo println ();. Ty z vás, kteří právě zajásali, že je Vala v oblasti parametrů stejná jako Python, budu muset bohužel zklamat. Nic jako println (text = msg); by vám neprošlo a kompilátor by si stěžoval, že nezná název text. Nicméně, pokud si ještě pamatujete, někde výše v tomto článku jsem psal, že Vala neumožňuje přetěžování metod, a nemůžeme tedy mít dvě metody se stejným názvem ale různým počtem parametrů. Častým důvodem použití takových metod je, že chceme dát volajícímu možnost vybrat si tu variantu, jež za něj nastaví předané parametry a zbývající nastaví na výchozí hodnoty. Právě tyto případy můžeme jednoduše pokrýt použitím parametrů s výchozí hodnotou. A nyní se můžeme přesunout k dalším dvěma funkcím:

    string raw_input (string prompt) {
        stdout.printf (@"$prompt ");
        var ret = stdin.read_line();
    
        return ret._strip();
    }
    
    bool positive_answer (string answr) {
        return (answr.down() == "y") || (answr.down() == "yes");
    }
    

    Zde snad jen krátký komentář, že metoda strip třídy string vrací nový řetězec s ořezanými přebývajícími bílými znaky na začátku i konci řetězce. _strip se liší pouze tím, že tuto úpravu dělá „in-place“, a mění tedy řetězec samotný ('_' na začátku názvu funkce/metody plní obvykle tento význam). Metoda down pak ve stejném duchu vrací nový řetězec, kde jsou všechna písmena převedena na malá. Poslední funkce v naší „knihovničce“ je trochu delší, ale o to důležitější. Budeme chtít, aby uživatel mohl zadávat na vstupu čísla. Zároveň ale budeme chtít zkontrolovat, jestli uživatel opravdu zadal číslo, a podle toho řídit běh programu.

    Vala nabízí funkci int.parse, která bere řetězec a vrací hodnotu typu int. Bohužel je však až příliš „bezpečná“, protože pokud předaný řetězec není řetězcovou reprezentací čísla, vrátí hodnotu 0 a programátor se nemá jak dozvědět, že při parsování nastal nějaký problém. A pokud je i 0 validním vstupem, ale potřebujete vědět, jestli uživatel opravdu zadal 0, nebo nějaký nečíselný řetězec, nechá vás Vala na holičkách. Proto budeme potřebovat následující funkci (a patřičnou výjimku):

    int checked_int_parse (string number_arg) throws ParsingError {
        unichar c;
        var number = number_arg.strip();
        int i = 0;
    
        if (number == "")
    	throw new ParsingError.NOT_A_NUMBER ("Empty string");
    
        number.get_next_char (ref i, out c);
        if (!(c.isdigit() || c == '-'))
    	throw new ParsingError.NOT_A_NUMBER ("Cannot parse: %s".printf(
    								number));
    
        for (; number.get_next_char (ref i, out c);) {
    	if (!c.isdigit())
    	    throw new ParsingError.NOT_A_NUMBER ("Cannot parse: %s".printf(
    								number));
        }
    
        return int.parse (number);
    }
    

    Navíc nám opět poslouží jako ukázka několika konstrukcí specifických pro Valu. Ve zkratce tato funkce z předaného řetězce ořeže bílé znaky, zkontroluje, jestli je prvním znakem '-' nebo číslice a dále pokračuje znak po znaku a kontroluje, jestli jsou to samé číslice. V případě, že narazí chybu, vyvolá výjimku („oficiálně“ se ve Vale používá název „chyba“) ParsingError. Pokud kontrola projde až za poslední znak, zavolá funkci int.parse, která se postará o převedení řetězce na číslo. Funkce checked_int_parse nás dostává k další oblasti, která zasluhuje komentář a vysvětlení. Určitě si všichni všimli, že při ořezávání předaného řetězce používáme metodu strip, tedy variantu bez podtržítka. A to z toho důvodu, že řetězce se, stejně jako ostatní objekty, předávají pomocí odkazu a „in-place“ varianta by tedy modifikovala předaný řetězec, což nemusí být žádoucí.

    Ve Vale existují různé možnosti, jak se předává parametr. Pokud funkce/metoda označí parametr jako ref, očekává, že bude inicializovaný a dává najevo, že jej může změnit (takto se implicitně předávají objekty). Pokud funkce/metoda označí parametr jako out, považuje jej za neinicializovaný a zavazuje se k tomu, že jej inicializuje. Pokud volající označí parametr jako ref, říká, že je inicializovaný a dovoluje metodě/funkci jej změnit. V případě out ze strany volajícího je, jak asi všichni čekáme, možno předat neinicializovaný parametr, u nějž očekáváme, že bude funkcí/metodou inicializován. Rozdíl mezi ref a out tedy určují jen to, kde se provádí testy na různost od null. Hodnotové typy (základní) se kopírují do lokálního prostoru funkce/metody.

    Věřím, že teď už vypadá srozumitelněji i volání metody get_next_char, ke kterému ještě dodám, že toto je doporučovaný způsob iterace přes znaky řetězce. Ptáte se proč nestačí obyčejný for-cyklus s inkrementací i1 a adresováním znaků pomocí [i]? Vysvětlením je to, že ve Vale jsou všechny řetězce implicitně v kódování UTF-8 (proto také typ unichar u proměnné c), a některé znaky tedy nemusí být jednobytové.

    Uživatelské rozhraní

    link

    Konečně se tedy dostáváme k uživatelskému rozhraní a samotné aplikaci DoNotForget. CLI využívá funkce z naší „knihovničky“ pomocných funkcí a je implementováno v souboru interfaces.vala, doporučuji prohlédnout si tento zdrojový kód celý. Novinek je pro nás zde jen pár, tak se na ně pojďme v rychlosti podívat. Naše první rozhraní využívá výčtový typ Responses, aby si jednotlivé části mohly předávat informaci o tom, jaký má být další krok z hlavní smyčky (while cyklu), kde jsou pomocí konstrukce switch volány jednotlivé podčásti. Implementace právě popsané části vypadá následovně:

    enum Responses {
        NONE,
        SHOW_COLLECTIONS,
        ADD_COLLECTION,
        REMOVE_COLLECTION,
        EDIT_COLLECTION,
        ADD_TASK,
        REMOVE_TASK,
        EDIT_TASK,
        ABOUT,
        QUIT
    }
    
    Responses response = main_menu ();
    
    while (response != Responses.QUIT) {
        println ();
        switch (response) {
    	case Responses.SHOW_COLLECTIONS: response = show_collections ();
    					 break;
    	case Responses.ADD_COLLECTION: response = add_collection ();
    				       break;
    	case Responses.REMOVE_COLLECTION: response = remove_collection ();
    					  break;
            case Responses.EDIT_COLLECTION: response = edit_collection ();
    					break;
    	case Responses.ADD_TASK: response = add_task ();
    				 break;
    	case Responses.REMOVE_TASK: response = remove_task ();
    				    break;
            case Responses.EDIT_TASK: response = edit_task ();
    					     break;
    	case Responses.ABOUT: response = show_about ();
    			      break;
    	case Responses.NONE: response = main_menu ();
    			     break;
    	default: assert_not_reached ();
        }
    }
    

    Věřím, že není třeba dalšího komentáře a vše je jasné přímo z kódu. Doporučuji udělat si klon repositáře z GitHubu (pokud jste tak ještě neučinili), prohlédnout si zdrojový kód, spustit příkaz make a trochu si s aplikací DoNotForget pohrát. Rozhodně není dokonalá a určitě jsou v ní chyby, ale jako ukázka možností Valy snad prozatím postačí. Budu samozřejmě vděčný za patche poslané na moji emailovou adresu. Pokud se vám stane, že příkaz make selže, zkontrolujte, jestli máte nainstalován překladač Valy a knihovnu libgee i s devel částí. Kdo by se chtěl vyhnout používání gitu, může si stáhnout archív odpovídající tagu pro tento článek v git repozitáři.

    A to je pro tentokrát vše, co se do článku vešlo. Doufám, že se mi podařilo ukázat základní prvky programovacího jazyka Vala a povzbudit alespoň pár čtenářů, aby o Vale uvažovali jako o jednom z kandidátů pro některý z příštích projektů. V dalším díle seriálu napravíme největší nedostatek aplikace DoNotForget přidáním ukládání dat do souboru a jejich opětovného načítání při spuštění. Při té příležitosti si ukážeme i práci s regulárními výrazy, argumenty příkazového řádku a jednoduchými konfiguračními soubory. No a samozřejmě se trochu více podíváme na knihovnu Gee a možnosti, které nabízí, protože bez vymožeností jako jsou množiny, mapy, seznamy apod. se dnes již téměř žádná aplikace neobejde. Konec konců i my jsme si v tomto díle již knihovnou Gee vypomohli pro náš TaskManager.

           

    Hodnocení: 80 %

            špatnédobré        

    Nástroje: Tisk bez diskuse

    Tiskni Sdílej: Linkuj Jaggni to Vybrali.sme.sk Google Del.icio.us Facebook

    Komentáře

    Vložit další komentář

    4.9.2012 00:59 weezy
    Rozbalit Rozbalit vše Re: Programování v jazyce Vala - základní prvky jazyka
    dalsi C like klon Delphi? clanok - pekny, jazyk - nuda
    4.9.2012 09:30 JS
    Rozbalit Rozbalit vše Re: Programování v jazyce Vala - základní prvky jazyka
    Je to klon C#, jinak +1 - nuda.
    4.9.2012 17:30 v.podzimek | skóre: 17
    Rozbalit Rozbalit vše Re: Programování v jazyce Vala - základní prvky jazyka
    Já myslím, ze Vala statečně zaplňuje místo mezi C++ a Javou.Samozřejmě ne v této
    C++ -- Vala -- Java
    
    pozici, ale v této
           Vala
           /  \
          /    \
       C++    Java
    
    pozici. ;) Teď vážně, myslím, že je to dobrý vysokoúrovňový jazyk, který ke svému rychlému běhu nepotřebuje žádný velký balast navíc.
    Jardík avatar 4.9.2012 01:50 Jardík | skóre: 40 | blog: jarda_bloguje
    Rozbalit Rozbalit vše Re: Programování v jazyce Vala - základní prvky jazyka
    public abstract Task? get (int index);
    Jenom int to může být, tralalala tralalala lala.
    Věřím v jednoho Boha.
    4.9.2012 17:35 v.podzimek | skóre: 17
    Rozbalit Rozbalit vše Re: Programování v jazyce Vala - základní prvky jazyka
    public abstract Task? get (int index);
    Jenom int to může být, tralalala tralalala lala.
    Nevím, jestli jsem správně pochopil tento komentář, ale pokud jde o to, že by ve Vale mělo být možné indexovat ([]) pouze hodnotou typu int, tak to bych rád uvedl na pravou míru. Vala totiž umožňuje použití libovolného typu, stačí správně zadefinovat metodu get. Ostatně i TaskManager má tuto metodu definovánu jako
    public new TaskCollection? get (string title)
    
    Pokud šlo o cokoliv jiného, omlouvám se za "nemístnou" odpověď. :)
    4.9.2012 18:13 luv | skóre: 18 | blog: luv
    Rozbalit Rozbalit vše Re: Programování v jazyce Vala - základní prvky jazyka
    int k indexovani pouzivaj jen 32bitovy smejdarny
    Luboš Doležel (Doli) avatar 4.9.2012 18:33 Luboš Doležel (Doli) | skóre: 98 | blog: Doliho blog | Kladensko
    Rozbalit Rozbalit vše Re: Programování v jazyce Vala - základní prvky jazyka
    To je náš Jardík. Ten akceptuje pouze 64bitové indexy ;-)
    Jardík avatar 4.9.2012 21:56 Jardík | skóre: 40 | blog: jarda_bloguje
    Rozbalit Rozbalit vše Re: Programování v jazyce Vala - základní prvky jazyka
    No spíš než ne-64bit indexy mi vadí předpoklady:

    sizeof vrací hodnotu typu int

    výraz sizeof(cokoliv) * něco_typu_int_který_může_být_záporný_a_dostanu_tak_kravinu je naprosto vpořádku a nemůže se stát nic špatného

    sizeof(int) <= sizeof(size_t)

    chci spojit pole, je ok udělat malloc(něco_typu_int+něco_typu_int) i když to třeba přeteče a smaže pak pevný disk. Nebo mi to třeba dá malloc(-1) a po převodu na size_t mi to hodí třeba nějaký 0xFFFFFFFFFFFFFFFF.
    using GLib;
    
    namespace bla
    {
    
    
    class Bla
    {
      static char[] join_array(char[] array1, char[] array2)
      {
        // TODO: copy elements
        int len = array1.length + array2.length;
        return new char[len];
      }
      
      public static void main(string[] args)
      {
        char[] array1 = new char[int.MAX];
        char[] array2 = new char[int.MAX];
        
        char[] array3 = join_array(array1, array2);
        
        stdout.printf("array1.length = %d, array2.length = %d, array3.length = %d\n",
          array1.length, array2.length, array3.length);
      }
    }
    
    }
    
    Mi vyprskne:
    (process:1800): GLib-ERROR **: gmem.c:195: failed to allocate 18446744073709551614 bytes
    
    Určitě né proto, že na mé platformě 2G+2G je 4G, ale proto, že to jaksi přeteklo, náhodou to nesmazalo pevný disk, pak se to převedlo na size_t (resp. gsize, protože to alokuje přes g_new0 z glib) a vyprsklo to kravinu. Kdyby vala používala size_t, tak by se toto na mé platformě nestalo a program by běžel správně. Vala tak na mé platformě uměle omezuje velikost pole na INT_MAX, ǎckoli pak vygeneruje C kód a to mě omezuje SIZE_MAX. Výsledkem je omezení na MIN(INT_MAX, SIZE_MAX), na mé platformě je INT_MAX menší.

    A když náhodou dám Vale hint, že array_length_type je size_t, tak si nepomůžu, stejně to přetypuje na int:
    [CCode(array_length_type = "size_t")]
      static char[] join_array([CCode(array_length_type = "size_t")] char[] array1, [CCode(array_length_type = "size_t")] char[] array2)
      {
        return new char[array1.length + array2.length];
      }
    
    
    // -->
    
    static gchar* bla_bla_join_array (gchar* array1, size_t array1_length1, gchar* array2, size_t array2_length1, size_t* result_length1) {
    	gchar* result = NULL;
    	gchar* _tmp0_;
    	gint _tmp0__length1;
    	gchar* _tmp1_;
    	gint _tmp1__length1;
    	gchar* _tmp2_ = NULL;
    	gchar* _tmp3_;
    	gint _tmp3__length1;
    	_tmp0_ = array1;
    	_tmp0__length1 = (gint) array1_length1;
    	_tmp1_ = array2;
    	_tmp1__length1 = (gint) array2_length1;
    	_tmp2_ = g_new0 (gchar, _tmp0__length1 + _tmp1__length1);
    	_tmp3_ = _tmp2_;
    	_tmp3__length1 = _tmp0__length1 + _tmp1__length1;
    	if (result_length1) {
    		*result_length1 = _tmp3__length1;
    	}
    	result = _tmp3_;
    	return result;
    }
    
    Věřím v jednoho Boha.
    Jardík avatar 4.9.2012 20:50 Jardík | skóre: 40 | blog: jarda_bloguje
    Rozbalit Rozbalit vše Re: Programování v jazyce Vala - základní prvky jazyka
    Né, mně jde o to, že vala pak generuje kraviny s intama místo se size_t, dementně si myslí, že sizeof() vrací hodnotu typu int, int násobí typem size_t, apod. vylomeniny. Pak z toho vyleze něco, co "náhodou funguje".
    Věřím v jednoho Boha.
    Bystroushaak avatar 4.9.2012 23:07 Bystroushaak | skóre: 32 | blog: Bystroushaakův blog | Praha
    Rozbalit Rozbalit vše Re: Programování v jazyce Vala - základní prvky jazyka
    Pěkný článek. Vala mi z něj přijde dost podobná D.
    Jardík avatar 5.9.2012 00:21 Jardík | skóre: 40 | blog: jarda_bloguje
    Rozbalit Rozbalit vše Re: Programování v jazyce Vala - základní prvky jazyka
    D alespoň používá size_t pro velikosti polí ^-^. (jardíkrejp).
    Věřím v jednoho Boha.
    Jardík avatar 5.9.2012 00:43 Jardík | skóre: 40 | blog: jarda_bloguje
    Rozbalit Rozbalit vše Re: Programování v jazyce Vala - základní prvky jazyka
    No ale když kouknu na standardní knihovnu jazyka D, tak asi ani vývojáři nevědí, proč tam ten size_t mají.

    Příkladem budiž třeba std.stream, kde třeba v konstruktoru BufferedStream je jako velikost bufferu typ ulong místo size_t (ulong nedává smysl pro velikost bufferu, size_t ano), seek se zdá ok (když vynechám u seekSet absolutní nastavení pozice jako znaménkovou hodnotu (a pak to vrací neznaménkovou) a size a position jako ulong. U seekSet by spíš bylo dobré ulong, u relativních seeků bych klidně long nechal. Pak najednou u File je property "available" jako size_t a popisek "returns the difference of the size and position". Při position 0 a size nějakých max_hodnota_ulong by to mohlo vracet kraviny na některých platformách.

    v std.thread nějak zapomínají na posix platformách volat pthread_attr_destroy po pthread_attr_init a vytvoření vlákna. Leaky!
    Věřím v jednoho Boha.
    Bystroushaak avatar 5.9.2012 00:44 Bystroushaak | skóre: 32 | blog: Bystroushaakův blog | Praha
    Rozbalit Rozbalit vše Re: Programování v jazyce Vala - základní prvky jazyka
    Pošli patch, komunita je dost otevřená.
    Jardík avatar 5.9.2012 01:01 Jardík | skóre: 40 | blog: jarda_bloguje
    Rozbalit Rozbalit vše Re: Programování v jazyce Vala - základní prvky jazyka
    tak patch na ten pthread_attr_destroy možná, jestli mě nebudou nutit registrovat se, ale patch pro ty věci ze std.stream ... by to rozbilo API, např. na x86-64 by to asi nevadilo, protože jsou stejně velký, ale na x86-32 by to vadit mohlo, 64bit ulong změnit na 32bit size_t ... a pak opačně u té available property.
    Věřím v jednoho Boha.
    Jardík avatar 5.9.2012 01:05 Jardík | skóre: 40 | blog: jarda_bloguje
    Rozbalit Rozbalit vše Re: Programování v jazyce Vala - základní prvky jazyka
    API, ABI, nebo oboje, to je jedno
    Věřím v jednoho Boha.
    4.9.2012 23:28 Ondra
    Rozbalit Rozbalit vše Re: Programování v jazyce Vala - základní prvky jazyka
    dobry den,

    zajmalo by me, zda-li se Vala (nebo i Genie) hodi pro psani knihoven at uz vysokourovnovych ci nizkourovnovych, jako treba GStreamer?

    nejsou nahodou v GNOME plany, ze by GStreamer a podobne do Valy prepsaly? prijde mi, ze jsou smutne zabugovany a takovej prepis do smysluplnejsiho jazyka by mohl pomoct :-D
    pavlix avatar 4.9.2012 23:38 pavlix | skóre: 54 | blog: pavlix
    Rozbalit Rozbalit vše Re: Programování v jazyce Vala - základní prvky jazyka
    Přepis do jiného jazyka nepomůže. Jinak „slušně zabugovaný“ znamená v případě GStreameru co? Já jsem si tuto otázku pokládal v souvislosti s NetworkManagerem v určitém ohledu by to mohlo být pohodlnější, ale...

    Výměna jazyka C za jazyk, který se do C teprve přeloží může přispět sice přispět k pohodlí programátora, nicméně nevyřeší chyby, které programátor vytváří, ani podle mě nijak nezmenší jeho lenost přemýšlet, či nedej bože něco po sobě otestovat.

    Nevím jak u GStreameru, ale u NetworkManageru je 100% nutná znalost jazyka C a použití jiného jazyka by vynucovalo znalost dvou jazyků. Naopak komplexita network managementu podle mě převyšuje žabomyší spory o jazycích, tudíž by opět změna zavedeného řádu neměla nejmenší šanci přinést významné zlepšení.

    To, co dělá GStreamer je podle mě opět podstatně komplexnější než network management. Takže bych rozhodně neviděl překážku v potřebě znát jazyk C a umět v něm pracovat s GObjecty.

    Celkově mi vychází, že u backendových aplikací jsou výhody marginální. Výhody se naopak projeví u frontendových aplikací, kde je potřeba vývoj a hlavně opravu chyb co nejvíce usnadnit.
    McBig avatar 5.9.2012 09:29 McBig | skóre: 5 | Nymburk
    Rozbalit Rozbalit vše Re: Programování v jazyce Vala - základní prvky jazyka
    Hezký článek, ale trochu mě to zarazilo s tím owned objektem. Vedle toho že sem byl doposud přesvědčen že je to obráceně, sem si to i ověřil na krátkém kódu:
    public class Boo : GLib.Object {
        string val;
        public Boo (string val) {
            this.val = val;
        }
    }
    
    public class Foo {
        private Boo _boo;
        public Foo (string val){
            _boo = new Boo(val);
        }
        public Boo boo {
            get { return _boo; }
            set { _boo = value; }
        }
        public void debug () {
            stdout.printf ("_boo addr: %p\n", _boo);
        }
    }
    
    void main () {
        var foo = new Foo("I'm foo");
        var tmp = foo.boo;
        foo.debug();
        stdout.printf ("temporary boo addr: %p\n", tmp);
        stdout.printf ("refcount: %u\n", tmp.ref_count);
        foo = null;
        stdout.printf ("temporary boo addr: %p\n", tmp);
        stdout.printf ("refcount: %u\n", tmp.ref_count);
    }
    
    Výstup si může každý otestovat sám:
    _boo addr: 0xd96e30
    temporary boo addr: 0xd96e30
    refcount: 2
    temporary boo addr: 0xd96e30
    refcount: 1
    
    Tedy, implicitně se vždy vrací owned, a pokud to má být jinak, musí se to vynutit. Obecně ale platí, že právě v případě různých Gee kontejnerů si na to prostě musí člověk dávat pozor, a vše hezky kontrolovat proti dokumentaci :)

    Pokud sem něco pochopil špatně, tak se omlouvám, ale z článku to takhle vyplývá.
    5.9.2012 10:32 v.podzimek | skóre: 17
    Rozbalit Rozbalit vše Re: Programování v jazyce Vala - základní prvky jazyka
    Tedy, implicitně se vždy vrací owned, a pokud to má být jinak, musí se to vynutit.
    On to s tím "implicitně" asi nebude tak jednoduché. V případě TaskCollection.dump se vrací nově konstruovaný string, který bez použití owned prostě zanikne s tím, jak skončí get blok. Pokud se v tomto případě owned vynechá, kompilátor hlásí warning a program segfaultuje. Stejně tak i tutoriál Valy říká:
    In contrast to normal methods, properties always have unowned return value.
    a také
    The keyword owned can be used to specifically ask a property to return a owned reference of the value, therefore causing the property value be reproduced in the object side.
    Ne že by to souhlasilo s výsledky toho příkladu...

    Založit nové vláknoNahoru

    ISSN 1214-1267   www.czech-server.cz
    © 1999-2015 Nitemedia s. r. o. Všechna práva vyhrazena.