Internet Info, s.r.o. Lupa Root Měšec Podnikatel DigiZone Slunečnice Vitalianew Bomba Navrcholu Weblogy Jagg Woko Dobrý web Computer.cz SK: MojeLinky
Root.czBlogyZmatení (programovacích) jazyků

Co nového v objektivním světě

zboj, 19. 03. 2012, 15:01 v kategorii Nezařazené,

Pokud vám to při čtení nadpisu nedošlo, tento článek pojednává o Objective-C, konkrétně o jeho nejnovější verzi, jak ji implementují nové LLVM a clang. ObjC se v posledních letech rychle vyvíjí z okrajové záležitosti v moderní jazyk a jako zatím poslední vylepšení nám vývojáři nabídli například nové literály pro práci se základními datovými strukturami.

Nové literály

Začněme trivialitami. ObjC má nové literály pro pole, asociativní pole a čísla reprezentovaná jako instance třídy NSNumber. Je to jen syntaktický cukr, nicméně už dlouho jsme čekali, abychom mohli místo

[NSNumber numberWithInteger: 1234]

psát

@1234

Trošku přehlednější, že? Stejně tak místo [NSArray arrayWithObjects: obj1, obj2, obj3, nil] teď použijeme @[obj1, obj2, obj3]. Podobný zápis mají asociativní pole: @{...}.

Navíc můžeme k prvkům pole přistupovat indexací pomocí hranatých závorek, tedy jako v každém jiném slušném programovacím jazyce, až už jde o Javascript, C++ nebo C#.

Lambda výrazy a bloky

Kdo používá C++, konečně se dočkal lambda výrazů podle nového standardu (C++11). Clang tak teď má dvojí syntax pro literály vyjadřující kus kódu. Toto rozšíření se netýká pouze ObjC, clang ale nyní umí také automaticky převést lambda výraz (např. [](){ return 1234; }) na clangovský blok, v tomto případě typu NSInteger(^)(). Sice vás nemusí zajímat, jak to funguje uvnitř, ale je poučné podívat se, jak toho překladač dosahuje. Celé to je až primitivní: lambda výraz se "zabalí" do bloku, ten se ve většině případů zkopíruje ze zásobníku na haldu a tam se předá automatické správě paměti. Z uvedeného vyplývá, že tato automatická konverze vyžaduje přítomnost ObjC runtimu (kvůli ARC) a v čistém C++ proto nefunguje (byť jak lambda výrazy, tak bloky v něm k dispozici jsou). Kopírování na haldu se neprovádí vždy, pokud překladač usoudí, že to není potřeba, zůstane blok na zásobníku.

Statistický strojový překlad

zboj, 16. 03. 2012, 12:21 v kategorii Zpracování přirozeného jazyka,

Nejlepší systémy pro automatický překlad jsou založeny na pravidlech (většinou na unifikační gramatice), nicméně vývoj takového systému je značně náročný na čas a především znalosti. Jako alternativa se v posledních dvou dekádách prosazují statistické metody zpracování přirozeného jazyka včetně strojového překladu.

Při překladu máme vstupní větu a chceme překlad. Chceme-li například přeložit větu e z angličtiny do češtiny, hledáme českou větu c, jež té anglické co nejlépe odpovídá. Ve formálním statickém vyjádření cheme najít větu s maximální hodnotou p(c|e), tj. pravděpodobností, že c je překladem e. Funkce pro překlad je tedy:

f(e) = argmaxc p(c|e)

Z praktických důvodů se pravděpodobnost převádí pomocí Bayesovy věty na p(e|c) p(c) / p(e). Pravděpodobnost p(e) je konstanta, takže ji můžeme ignorovat (dělení kladnou konstantou je monotónní, můžeme ji tedy ignorovat při hledání maxima). Výraz se tak zjednodušil na součin pravděpodobnosti překladu (z češtiny do angličtiny) a pravděpodobnosti existence (resp. gramatikality) českého překladu. První pravděpodobnost se počítá na základě překladového modelu získaného z paralelního (dvoujazyčného) korpusu. Druhá pravděpodobnost je daná modelem pro jeden jazyk (v tomto případě cílový).

O překladovém modelu zde psát nebudu, problematika je příliš složitá a těžko bych ji mohl vysvětlit někomu bez hlubokých znalostí statistiky a lingvistiky. U jednojazyčného modelu je naštěstí situace velmi jednoduchá. Každá věta je seznamem slov a tedy

p(c) = p(w1) p(w2|w1) p(w3|w1,w2) ... p(wn|w1...wn-1)

Reálně není pochopitelně možné pracovat s takovýmito podmíněnými pravděpodobnostmi. Je nutná aproximace a proto se pracuje s n-gramy (např. s trigramy). Výraz se proto zjednoduší takto:

p(c) = p(w1) p(w2|w1) p(w3|w1,w2) ... p(wn|wn-2,wn-1)

Potud krásná teorie. Bohužel pravděpodobnosti jsou malá čísla a pokud je násobíme na počítači, celkem rychle skončíme na nule. Zde pomůže znalost středoškolské matematiky. Při hledání maxima funkce f můžeme stejně dobře hledat maximum funkce log f, protože logaritmus je monotónní funkce. A protože logaritmus součinu je roven součtu logaritmů, můžeme bez ztráty přesnosti pracovat se součty logaritmů pravděpodobností (což už počítač zvládne) a dojdeme ke stejnému výsledku.

Výše jsem pouze nastínil, jak se pracuje se statickými modely, problematika je pochopitelně mnohem komplikovanější. Důkazem toho, že to celé funguje, je například Google Translate.

Jak na unifikační gramatiku

zboj, 27. 02. 2012, 17:36 v kategorii Zpracování přirozeného jazyka,

Unifikační gramatiky jsou skupinou (většinou) bezkontextových gramatik rozšířených o datové struktury (typicky struktury rysů), nad nimiž je definována operace unifikace. Jejich důležitou vlastností je, že byť obsahují pouze bezkontextová pravidla (typu X→α), jejich formální síla je větší než u běžných bezkontextových gramatik. Jinými slovy, generují i jazyky, které nejsou bezkontextové (to ovšem nutně neznamená, že generují všechny kontextové jazyky).

Unifikačních gramatik je mnoho, zde se zaměřím na formalismus nazvaný Lexical Functional Grammar (LFG). LFG byla navržena jako formální prostředek pro zpracování přirozeného jazyka, jakmile se ukázalo, že Chomského gramatiky nejsou pro tuto úlohu ideální. Zajímavou vlastností definice LFG je, že celý formální aparát je paradoxně definován bez operace unifikace (lze ale ukázat, že způsob, jakým funguje, je ekvivalentní unifikaci, což je také nejčastější způsob, jak LFG implementovat). I když není LFG vždy lingvisticky adekvátní, výhody jejího formálně precizního návrhu převažují.

Základní vlastností těchto gramatik je, že narozdíl od programovacích jazyků nejsou jednoznačné (pro vstupní řetězec může existovat více složkových syntaktických stromů). To je dáno víceznačností jazyků na úrovni slovní zásoby (kolej jako kus železa vs. ubytovací zařízení), tvarosloví (ženu jako sloveso vs. 4. pád podstatného jména žena, což je mimochodem přechodník, který ale většina Čechů neumí používat), skladby (Time flies like an arrow, kde slovesem je buď flies nebo like; oblíbeným příkladem v češtině je věta Ženu holí stroj) i významu (sémantické roviny). Z tohoto důvodu se také používají úplně jiné algoritmy než pro parsing programovacích jazyků.

LFG se, zjednodušeně řečeno, skládá z lexikonu (morfolexikálních položek) a vlastní gramatiky (pravidla s unifikačními anotacemi). Architektura LFG je tedy modulární, což je pro implementaci výhodou (princip "rozděl a panuj" při vývoji programů). Precizní formální popis přínáší několik výhod, kromě snadné implementovatelnosti například konkretizaci pojmů jako autosémantický a synsématický (angl. content word vs. function word). Modulárnost také usnadňuje "portování" gramatik z jednoho jazyka na jiný, např. pro češtinu a slovenštinu jsou pravidla a jejich anotace stoprocentně shodná (protože neexistují rozdíly ve skladbě), v rámci LFG gramatiky se oba jazyky liší pouze morfolexikálně (jediným rozdílným modulem je lexikon).

Pro seznámení se základní architekturou LFG a jejím historickým pozadím je nejlepší kniha The Mental Representation of Grammatical Relations (ed. Joan Bresnan, přinejmenším stěžejní článek je volně ke stažení), z novějších publikací pak sborníky LFG Conference (rovněž volně ke stažení). Jako velmi jednoduchý příklad uveďme pravidlo pro jmennou frázi skládající se z číslovky, přídavného jména a podstatného jména, ve kterém se bere ohled na shodu v rodě, pádě a čísle.

NP (Num) A* N
(↑NUM)=↓ (↑ADJ)∋↓

(↑GENDER)=(↓GENDER)

(↑NUMBER)=(↓NUMBER)

(↑CASE)=(↓CASE)

↑=↓

Jak je vidět, číslovka je nepovinná a přívlastků může být ve jmenné frázi libovolné množství (nebo žádný, což zajistí Kleenova *). Podstatné jméno je hlavou pravidla (struktura pro NP se unifikuje se strukturou pro N: ↑=↓) a přídavné jméno se musí s podstatným jménem shodovat v řadě morfologických vlastností (jmennou frází je tedy podle tohoto pravidla např. velký dům a velkého domu, ale ne velký domu nebo velkého dům).

Jazyky se obecně dělí na endocentrické a lexocentrické, i když toto dělení není striktní a jde spíše o stupnici "lexocentricity". Čeština je spíše lexocentrická, neboť má bohaté tvarosloví a značně volný pořádek slov. Typickým zástupcem endocentrických jazyků je angličina s pevným pořádkem slov a velmi omezeným tvaroslovím (nebo čínština, jež flexi nemá vůbec).

Přirozený jazyk a bezkontextová syntax

zboj, 18. 02. 2012, 19:00 v kategorii Zpracování přirozeného jazyka,

Zpracování přirozeného jazyka patří k nejsložitějším algoritmickým úlohám. V přirozených jazycích se střetává tendence vyjádřit co nejvíce co nejpřesněji s ekonomickým principem, tedy tendencí slovní vyjádření redukovat (neformálně můžeme mluvit o lenosti). Lidské jazyky jsou proto (narozdíl od formálních) víceznačné na všech úrovních, které jazykověda rozlišuje (tvarosloví, syntax, sémantika), čehož důsledkem jsou problémy s formálním popisem jazyka a jeho strojovým zpracováním.

Když Noam Chomsky představil vědecké obci své formální gramatiky (předtím byla formální jazykověda výrazně strukturální nebo funkcionální), znamenalo to malou revoluci (kromě jazykovědy i v informatice). Chomsky se při popisu jazyka (téměř výlučně angličtiny) zaměřil na gramatiky bezkontextové, byť se záhy ukázalo, že většina jazyků bezkontextová není. Navíc Kenneth Hale ukázal, že mnohé jazyky nejsou konfigurační (včetně jazyků slovanských, tedy i češtiny), a složková (frázová) syntax tak zachycuje pouze slovosled.

Z Chomského generativní gramatiky vyšlo mnoho moderních teorií popisu jazyka. V dalším článku se zaměřím na LFG (Lexical Functional Grammar), v tomto na X'-teorii (čti: X bar theory). Jako českou kuriozitu lze zmínit Funkční generativní popis prof. Sgalla, o tom ale jindy.

X'-teorie vychází z předpokladu, že věty a fráze mají téměř vždy hlavu, tj. element, jenž nějakým způsobem dominuje zbytek fráze. Ve jmenných frázích je touto hlavou podstatné jméno, ve větách sloveso (finitní) apod. Zavádí proto úrovně neterminálů, které označuje znakem ' (proto X'). Maximální projekce neterminálu X se označuje XP (ekvivalent k X'', obvykle je nejvyšší úrovní ta třetí). Bezkontextová pravidla jsou pak omezena na typ

Xn+1 → Xn YP

a

XP → YP Xmax-1

přičemž YP v prvním pravidle se nazývá komplement a v druhém specifikátor (angl. specifier). Projekce kategorie X je pak hlavou pravidla.

Je zřejmé, že se jedná o běžnou bezkontextovou gramatiku s obyčejnými neterminály, jejíž pravidla jsou však pouze specifického typu. Stále se jedná o způsob zápisu jazyků orientovaný na angličtinu, a tedy nevhodný pro nekonfigurační jazyky. O vhodnějším modelu pro mnohem širší spektrum jazyků (a jeho implementaci v C++) přístě.

Všudypřítomná harmonie

zboj, 11. 01. 2012, 18:15 v kategorii Programovací jazyky,

K nejrozšířenějším jazykům dneška patří JavaScript (JS). Navzdory svému jméno se od Javy dost liší, sdílí s ní v podstatě jen céčkovou syntax. Byl kodifikován pod názvem ECMAScript a nedávno jsme se dočkali verze 5,1.

Verze 5,1 je jen mírným pokrokem, daleko větším měl být JS 4,0, jejž ovšem Microsoft jako normu zablokoval (nelíbilo se mu, že by se Adobe prosadilo se svým ActionScriptem). Nakonec se všichni velcí hráči shodli (a podle této shody novou verzi pojmenovali Harmony), nicméně oficiální posvěcení ve formě kodifikace stále chybí a implementace v prohlížečích je v nedohlednu.

Harmony přináší třídy (a odpovídající "neprototypovou" dědičnost), jmenné prostory, typovou kontrolu atd. To vše už tu jako návrh (JS4) nějakou dobu bylo, takže existuje pár více či méně tuto specifikaci naplňujících implementací.

Flash

Adobe se Harmony inspirovalo při návrhu ActionScriptu. Ve Flashi tak máte k dispozici plnohodnotný jazyk založený na virtuálním stroji s mnoha knihovnami.

.NET

Microsoft pro svůj .NET vytvořil překladač JScript.NET pro JS se syntaxí podobnou Harmony. Tento překladač generuje bajtkód (MSIL), takže v něm napíšete téměř vše, co v C#. Především lze využívat BCL. Bohužel vývoj se zastavil u verze .NET 2,0.

Prohlížeč

Prohlížeče Harmony nativně nepodporují, existují ale nástroje pro překlad do "prostého" JS. Jedním z nich je Google Traceur, dalším například Mascara. Celé to funguje jako GWT (které překládá z Javy) a podobné transpilery. Narozdíl od JScript.NET není k dispozici standardní knihovna, jste odkázáni na API třetích stran (případně CommonJS).

Vazba na C a Javu

V céčku či Javě lze JS spouštět pomocí knihoven. Pro Javu se používá především Rhino, pro C/C++ můžete použít V8 (překládá JS do nativního kódu) nebo JavaScriptCore (podle verze interpretuje, překládá do bajtkódu nebo do kódu procesoru). Sice neumí nativně Harmony, ale "transpilovaný" kód běží bez problémů. Tento postup využívá například Titanium pro běh aplikací na Androidu a iOS.

Frázové a abstraktní syntaktické stromy

zboj, 2. 01. 2012, 19:09 v kategorii Nezařazené,

Pod článkem o Jisonu se rozvinula zajímavá diskuse, navážu proto na tématiku stručným vysvětlením rozdílu mezi abstraktní a frázovou syntaxí.

Nejprve je třeba ujasnit si terminologii, která je tu mírně zmatená. Frázové stromy se tak nazývají podle frázové gramatiky, která se definuje pro každý formální jazyk. V literatuře je najdete také pod názvem "konkrétní" stromy (jako protiklad k abstraktním). Abstraktní syntaktické stromy (anglicky Abstract Syntax Tree, odtud často používaná zkratka AST) se odvozují z frázových a lze je přímo použít pro interpretaci jazyka (nebo kompilaci).

Parsingu zpravidla předchází lexikální analýza, jejímž výstupem je seznam tokenů (u programovacích jazyků bývá gramatika jednoznačná). Počet tokenů je stejný jako počet listů frázového stromu. Listy jsou ohodnoceny vstupními tokeny, ostatní vrcholy stromu jsou ohodnoceny neterminály gramatiky, na jejímž základě byl strom vytvořen.

Abstraktní strom obsahuje menší počet vrcholů, je roven nanejvýš počtu tokenů. Převod z frázového na abstraktní strom je plně automatický a není ovlivněn sémantikou jazyka. Každému frázovému stromu přitom odpovídá právě jeden abstraktní, opačně to ale samozřejmě neplatí.

S přihlédnutím k sémantice lze definovat ekvivalenci abstraktních stromů, např. vzhledem k vlastnostem operace sčítání jsou abstraktní stromy pro výrazy (a+b)+c a a+(b+c) ekvivalentní, pro mínus to už ale neplatí. Frázový strom těchto výrazů bude mít 10 vrcholů, abstraktní 5.

Při převodu na abstraktní strom se určuje hlava pravidla, což je většinou operátor nebo jméno funkce (u volání funkce). V příkladu výše by to byl operátor +.

V závislosti na sémantice se abstraktní stromy po parsingu ve fázi optimalizace upravují (některé podstromy např. nejsou potřebné). Interpretace abstraktního stromu je přímočará (fungují tak interprety Javascriptu), při kompilace se používá většinou mezikód, a to buď explicitní (např. bajtkód v .NETu či Javě), nebo implicitní (vnitřní reprezentace kódu, jako např. v LLVM).

Frázové stromy při implementaci interpretu nebo překladače v podstatě nikdy nevidíme, jsou jen jakousi imaginární datovou strukturou, již generuje gramatika, vlastní parser generuje přímo AST. Navíc často splývá syntax a sémantika. Pokud si chcete vyzkoušet, jak se netriviální gramatika implemetuje, doporučuji třeba ANTLR.

Postavte si jazyk

zboj, 21. 12. 2011, 00:16 v kategorii Pokročilé techniky,

Vývojáři jsou lid kreativní, a jak lépe vybít svou kreativitu, než vytvořením vlastního jazyka? Teď nechci nabádat k vynalézání kola, sám jsem vymyslel v životě kdysi dávno jen jeden jazyk, a to jen proto, že to bylo nutnou podmínkou pro zápočet, všechny ostatní překladače, které jsem kdy napsal, měly za cíl jazyky již existující a nanejvýš mírně upravené. Zde stručně popíšu, jak jednoduše napsat vlastní parser a s ním interpret nebo transpiler.

Nemusíte vědět, kdo je Noam Chomsky, ale měli byste tušit, co je formální gramatika. Regulární jazyky zná asi každý, kdo programuje, tak vězte, že bezkontextové gramatiky jsou něco podobného, jen mají větší generativní sílu. Profíci používají flex a yacc nebo bison či podobné nástroje. Mnohem snazší je ale začít s nějakým skriptovacím jazykem. Vezměme Javascript (JS).

Javascript bez prohlížeče

Kopií bisonu pro JS je jison (snadno vygooglíte). Následuje jednoduchá gramatika pro aritmetické výrazy.

var Parser = require("jison").Parser;
var grammar = {
"lex": {
"rules": [
["\\s+", "/* skip whitespace */"],
["[0-9]+(?:\\.[0-9]+)?\\b", "return 'NUMBER';"],
["\\*", "return '*';"],
["\\/", "return '/';"],
["-", "return '-';"],
["\\+", "return '+';"],
["\\^", "return '^';"],
["\\(", "return '(';"],
["\\)", "return ')';"],
["PI\\b", "return 'PI';"],
["E\\b", "return 'E';"],
["$", "return 'EOF';"]
]
},

"operators": [
["left", "+", "-"],
["left", "*", "/"],
["left", "^"],
["left", "UMINUS"]
],

"bnf": {
"expressions": [["e EOF", "return $1;"]],

"e": [["e + e", "$$ = $1 + $3;"],
["e - e", "$$ = $1 - $3;"],
["e * e", "$$ = $1 * $3;"],
["e / e", "$$ = $1 / $3;"],
["e ^ e", "$$ = Math.pow($1, $3);"],
["- e", "$$ = -$2;", { "prec": "UMINUS"}],
["( e )", "$$ = $2;"],
["NUMBER", "$$ = Number(yytext);"],
["E", "$$ = Math.E;"],
["PI", "$$ = Math.PI;"]]
}
};

První řádek předpokládá, že již máte nainstalovaný jison. Ten funguje například s narwhalem (pomalý, nedoporučuji) nebo s nodejs (to je interpret JS postavený nad superrychlým V8 od Googlu, opět snadno vygooglíte). Gramatiku můžete velice jednoduše interpretovat takto:

var parser = new Parser(grammar);
var result = parser.parse("2 + 3");
console.log(result);

Teď máme prakticky zadarmo interpret, možná si ale říkáte, že nutnost mít nodejs (nebo něco podobného) je svazující. To je v podstatě pravda, ale jakmile gramatiku odladíte, není nic snazšího než použít metodu generate:

parser.generate();

Výslednému kódu sice asi nebudete rozumět, ale podstatné je, že se tak zbavíte závislostí na nodejs. Vygenerovaný kód v JS bez problémů interpretuje libovolný moderní prohlížeč, dokonce i MSIE 6 (ten ovšem trošku pomaleji).

Parsing mimo prohlížeč

Kromě prohlížečů můžete kód použít i v nativní aplikaci. Jednou z možností je využít V8, což je interpret JS od Google, zadarmo a rychlý. Vlastně ani ne interpret, většina kódu se totiž překládá do nativního kódu pro Intel nebo ARM. V8 můžete ke své aplikaci staticky přilinkovat (osobně vyzkoušeno pro iOS), nevýhodou je jen větší velikost binárky.

V aplikacích pro Windows můžete využít JScript.NET. K vygenerovanému kódu přidáte toto:

import System;
package ParserDemo {
public class Parser {
public function Parse(s:String) {
return parser.parse(s);
}
}
var p = new ParserDemo.Parser();
Console.WriteLine(p.Parse("2 * 3"));

Překladač jsc vygeneruje spustitelný soubor, můžete také vygenerovat dynamickou knihovnu (DLL) a tu volat z kódu v C#, VB, C++/CLI atd. V tomto případě můžete použít volbu /fast+, což znamená, že výsledkem překladu bude čistý MSIL (CIL) kód, tedy žádný interpretovaný JS, ale plnohodnotný bajtkód, jejž JIT před spuštěním přeloží do nativního kódu.

Jak vidíte, napsat si jednoduchý interpret nebo transpiler není vůbec složité. Do nástrojů jako Google Web Toolkit (GWT) to má sice prozatím daleko, ale první krok bychom již měli.

IAsyncOperation<WTF>

zboj, 16. 12. 2011, 13:42 v kategorii Programovací jazyky,

Jak ve WinRT získáte seznam souborů v adresáři? V C# nějak takto:

var folder = KnownFolders.PicturesLibrary;
var files = await folder.GetFilesAsync();
foreach (StorageFile file in files) { /* ... */ }

A jak to bude vypadat v C++/CX?

auto folder = KnownFolders::PicturesLibrary;
auto op = folder->GetFilesAsync();
op->Completed = ref new AsyncOperationCompletedHandler<IVectorView<IStorageFile^>^>(
[](IAsyncOperation<IVectorView<IStorageFile^>^> op) {
if (op->Status == AsyncStatus::Completed) {
auto files = op->GetResults();
/* ... */
}
});
op->Start();

Zdá se mi, že soudruzi v Redmondu by měli ještě trochu zapracovat na své verzi C++, než vypustí první betaverzi.

Jak (ne)optimalizovat spotřebu paměti v .NET

zboj, 13. 12. 2011, 23:13 v kategorii Pokročilé techniky,

Dnes jen krátce a ke konkrétnímu tématu. Jak známo, velké objekty GC na haldě nepřesouvá, takže pokud si je budete alokovat a uvolňovat sami, nezpůsobíte svým počínáním větší fragmentaci než GC. Právě velké objekty je vhodné uvolnit co nejdříve a pokud možno deterministicky. To není v .NET problém, na neřízené haldě lze alokovat třeba i sto MB a díky IDisposable paměť uvolnit, jakmile objekt nepotřebujeme. Můžeme mít tedy ve třídě nějaký pointer:

private: Neco* ptr;

Ten alokujeme v konstruktoru a uvolňujeme v destruktoru, tedy Dispose:

~Trida() { delete ptr; ptr = nullptr; }

Potíže nastanou, pokud nedisciplinovaný programátor objekt explicitně nezruší. Na první pohled vhodné řešení s finalizérem může být fatální:

!Trida() { delete ptr; }

Tím sice teoreticky zamezíme únikům paměti, jenže GC na neřízenou haldu zvysoka, ehm, kašle, takže dříve než úklidu se dočkáte výjimky OutOfMemoryException. Mnohem lepší je vyhodit ve finalizéru výjimku:

!Trida() { throw gcnew Exception("Object not disposed properly"); }

Nezlikvidovat náležitě objekt je pochopitelně chyba programátora, ale pořád se najdou jedinci, kteří nečtou dokumentaci, případně v životě neslyšeli o using, takže naservírováním výjimky, která s přehledem odstřelí celou aplikaci, jim vlastně děláte laskavost.

.NET aneb cesta tam a zase zpátky

zboj, 12. 12. 2011, 12:23 v kategorii Nezařazené,

Windows vznikaly od počátku v jazyce C, je proto logické, že i rozhraní pro psaní aplikací bylo (a dodnes je) v céčku. Toto Windows API, později nazývané Win16, nebylo nijak extra dobře navržené, ale protože Microsoft vždy kladl důraz na zpětnou kompatibilitu, vydrželo (v rozšířené formě nazývané Win32) až do dnešních Windows 7 (a jeho podmnožinu najdeme i v Metru).

COM, DCOM, COM+

S rozmachem objektově orientovaného programování začaly vznikat různé nadstavby i nad WinAPI, vesměs v C++. V 90. letech navíc začaly vznikat rozsáhlé objektové systémy založené na komunikaci mezi nezávislými komponentami, v podstatě každá důležitá IT firma měla svůj: Sun měl NEO (přejmenované DOE=Distributed Objects Everywhere), v IBM měli SOM (System Object Model), NeXTStep vytvořil PDO (Portable Distributed Objects) atd. Odpovědí Microsoftu na tento trend byl Component Object Model (COM).

Stejně jako se zkušení vývojáři smáli složitosti kódu pro "hello world" ve WinAPI, dělali nyní to samé při porovnání COM a PDO, protože v prvně jmenovaném byl kód se stejnou funkčností cca. 10x větší. Dělat s COM bylo vskutku složité a i když později to usnadňovaly některé vývojové nástroje, nikomu tato technologie asi k srdci nepřirostla.

Variantou COM byl DCOM (distribuovaný COM) a nakonec COM+ spojující obě sesterské technologie.

.NET

Když soud zatrhnul Microsoftu upravit si Javu, pustili se v Redmondu do vývoje vlastního virtuálního stroje a jazyka nad ním. V roce 2002 představený .NET s novým C# a knihovnou BCL byly ve své první verzi jen obyčejnou kopií Javy, nicméně v následujících deseti letech byl vývoj značně dynamičtější než u Javy a dnes je Java minimálně o generaci pozadu.

Na přelomu tisíciletí se obecně predpokládalo, že .NET ve Windows nahradí WinAPI a jednoho krásného dne bude i jádro Windows běžet v řízeném kódu (takový experimentální systém v MS skutečně existuje). Bohužel (nebo bohudík) i Windows 7 jsou založené na WinAPI a od MS téměř žádné aplikace v .NET dodnes nemáme. Jiní vývojáři sice občas s něčím v .NET přijdou, ale problémy s instalací runtimu spolehlivě odrazují od .NET, má-li být výslednou aplikaci schopen nainstalovat každý běžný uživatel (o jejichž inteligenci se tu asi rozepisovat nemusím).

Azure a Windows Phone 7

Postavit Azure nad .NET bylo jistě velmi snadné rozhodnutí, Ballmer teď může tvrdit, že .NET je úspěšným projektem, protože na něm jede v rámci Azure spousta aplikací.Povolil tak tlak na WinDiv, jež vždy tíhla k nativnímu kódu, aby více využívala .NET, a zároveň má DevDiv (jež vyvíjí .NET a věci kolem) záminku k existenci.

Proti Flashi se snažil MS bojovat také pomocí .NET a vyvinul Silverlight. Ten se sice na webu neujal, ale našel uplatnění alespoň jako runtime pro Windows Phone 7. Relativní úspěch Azure se ale asi opakovat nebude, neboť ve Windows Phone 8 bude .NET nahrazenen novým WinRT.

WinRT a "nové" C++

S trochou nadsázky se dá říci, že .NET měl být jednodušší a modernější náhradou za COM. Svým způsobem i byl a v serverovém prostředí bychom těžko hledali lepší konkurenci k Javě. Jenže dnešním trendem jsou mobilní technologie a jak v MS veřejně připouští, .NET se na relativně pomalá zařízení s omezeným množstvím paměti nehodí.

Nástupcem zastaralého WinAPI má být WinRT (jak jsem už zmínil, před několika lety to měl být .NET). WinRT je zbrusu nové jádro s API postaveným na, a teď pozor, staré dobré technologii COM. Největší nevýhodu COM, složitost pro vývojáře, má odstranit "nové" C++ (píšu v uvozovkách, protože skutečné nové C++ je pro mě C++11), označované dříve WinC++ a nyní C++/CX. Jde o C++ s rozšířenou syntaxí pro COM komponenty (teď se ovšem nazývají WinRT komponenty). Z .NET se do WinRT dostal pouze formát metadat popisující rozhraní komponent. Existuje sice tzv. projekce nového WinRT do C# a VB, jenže jejich knihovna (BCL) je natolik omezená, že existující kód pro .NET bez úprav nepřeložíte.

Microsoft tak během deseti let udělal zajímavé kolečko. Opustil COM, vyvinul .NET a věci kolem, uplatnil jej v serverových produktech a, paradoxně, v operačním systému pro mobily, aby se nakonec pokorně vrátil k nativnímu a jen mírně modernizovanému COM. Nabízí se srovnání s Applem, který šel místo několika veletočů cestou evoluce a od koupě OpenStepu v roce 1996 pracuje stále se stejnou technologií, již postupně modernizuje. Místo bajtkódu se používají "tlusté" binárky (fat binary), takže lze jeden soubor spustit na různých procesorech (dříve PowerPC a Intel, dnes to samé používají pro ARMv6 a ARMv7), runtime sice nezpracovává bajtkód, ale nemá žádnou nevýhodu oproti VM s JIT, správa paměti je pro programátora stejně nenáročná jako v .NET atd. Buďme rádi, že je Microsoft (nebo aspoň jeho akcionáři) schopen sebereflexe a vrací se k osvědčené technologii.