1) DLR - Úvod do implementace .NET jazyků
english version >
Tento tutoriál je zaměřen na vývoj vlastního programovacího jazyka na platformě .NET s použitím nového frameworku Dynamic Language Runtime (DLR) od Microsoftu. DLR je zaměřený zejména na implementaci dynamických jazyků, které implementovat na .NETu bylo problematické a DLR poskytuje řadu funkcí, které vývoj dynamických jazyků zjednoduší.
Proč vlastní .NET jazyk?
Důvodem jsou většinou tzv. domain specific languages (DSL), do češtiny volně přeložené jako jazyky specifické pro určitou oblast. Typickým zástupcem DSL je jazyk SQL - dotazovací jazyk šitý na míru relačním databázím. Dalšímy příklady jsou například ColdFusion markup language či třeba unixové awk, ls,sort, wc atd.
Z praxe bych se pak zmínil třeba o přednášce vývojáře z jedné holandské banky, ve které bankéři každý den dělali výpočty založené na mnoha ekonomických faktorech. Pro programátory bylo težké nové formule implementovat, protože neměli potřebné ekonomické znalosti. Naopak ekonomové samozřejmě zase měli problémy s programováním i když měli k dispozici framework vyvinutý přímo pro jejich práci. Nakonec se rozhodli implementovat vlastní “programovací“ jazyk na výpočty pro ekonomy, který vyřešil tento problém.
Výhody těchto jazyků oproti jazykům s všeobecným zaměřeným (general purpose languages) jako jsou C, Java, C# atd. je zjednodušení jazyka na míru abstrakce potřebné pouze pro danou problematiku. Zjednodušení vede k rychlejšímu vývoji, kvalitnějšímu kódu, méně chybám a pod. Nevýhodou je naopak náročnost vývoje jazyka a chybějící nástroje jako například vývojové prostředí s podporou IntelliSense, kterým již rozšířené jazyky většinou disponují.
Proč dynamické jazyky
Dynamické jazyky jsou flexibilnější a ohebnější než jazyky statické, navíc programování je řekněme méně restriktivní a rychlejší. Mezi dynamické jazyky můžeme zařadit Python, Ruby, PHP atd. Naopak argument proti dynamickým jazykům je dynamické typování proměnných, které může vést k častějším chybám.
Jak funguje .NET
Základem .NETu je jazyk CIL, což je „univerzální“ programovací jazyk jehož kód umí .NET Framework (resp. jeho část Common Language Runtime - CLR) vykonat. Programátoři ale nepíší kod v CILu, který je spíše podobný assembleru, ale píší kód v .NET jazyce jako například C#, VB.NET či F#, který je následně převeden kompilátorem do CILu. To umožňuje programátorům použít jakýkoliv .NET jazyk pro vývoj.

- Kompilátor přeloží kód v C#, VB.NET či jiném .NET jazyce do jazyka CIL
- CIL kód může být vykonán na každém počítači s nainstalovaným CLR (součástí .NET Frameworku)
CIL
Jak už bylo zmíněno, CIL je “univerzální” jazyk nižší úrovně podobný assembleru. Co je ale důležité, jedná se o statický jazyk, což může být problém, ale k tomu se dostanu později…
Zde je ukázka C# kódu převedeného do jazyka CIL:

CIL je statický jazyk - add je matematická operace očekávající dvě číselné hodnoty na zásobníku a volaná metoda Console.WriteLine() očekává integer.
Přeložit C# do CILu není pro kompilátor problém, protože se jedná taktéž statický jazyk.
Dynamické jazyky
Neexistuje přesné pravidlo definující striktně zda je jazyk dynamický či statický. Nicméně pro dynamické jazyky jsou většinou charakteristické určité vlastnosti jako změna datových typů za běhu aplikace či dynamicky typované proměnné. Dynamické typování je jeden ze základních problémů při vývoji dynamických jazyků na .NETu, protože zatímco statický jazyk CIL při deklarování proměnné vyžaduje určit datový typ, u dynamických jazyků je typ proměnné znám až za běhu a navíc se může změnit. Problém tedy je, že kompilátor takového dynamického jazyku neví, jak má dané proměné v CILu nadeklarovat, když nezná jejich typ.
Ukázka JavaScriptu (dynamický jazyk):
if (Math.random() < 0.5)
var x = 5;
else
var x = "abc";
var res = x + x;
V tomto případě je obtížné vygenerovat odpovídající CIL kód pro takovýto příklad, protože proměnná x může být buď řetězec nebo číslo (o tom je rozhodnuto až za běhu aplikace). Další problém je část x + x, kde operace + může být buď aritmetický součet dvou čísel nebo spojení dvou řetězců, ale pro tyto dvě operace má CIL dvě odlišné instrukce a tak nelze jednoduše vygenerovat odpovídající CIL kód pro tuto operaci.
To ale neznamená, že by nebylo možné implementovat dynamické jazyky na .NETu. Ještě před DLR už existovali dynamické jazyky jako Ruby.NET či Phalanger (PHP) pro .NET, takže musí existovat způsoby jak obejít i zmíněné problémy. Například pro operátor + ve zmíněném JavaScriptovém příkladě by bylo možné vygenerovat metodu AddObjects(object, object), která až za běhu rozhodne o tom, zda má hodnoty aritmeticky sečíst nebo spojit v závislosti na typu předaných parametrů:
Nyní operace + může být přeložena na:
call void [myProject]MyCompiler::AddObjects(object, object)
Zde jsem se tedy pokusil nastínit, s jakými problémy se doposud museli vývojáři dynamických jazyků na .NETu poprat. Navíc toto řešení je, co se výkonu týče, celkem pomalé, protože .NET podporuje hned několik číselných typů jako Int32, Int64, double, float atd. a pro každý typ by bylo potřeba vygenerovat další if-else podmínky v metodě AddObject(). Za běhu aplikace je pak testování těchto podmínek časově náročné.
Dynamic Language Runtime
Microsoft vyvinul framework pro vývoj dynamických jazyků DLR, který implementaci jazyků a jejich dynamických vlastností zjednodušuje a co je důležitější, obsahuje řadu mechanismů eliminujících problémy s rychlostí (například zmíněné if-else podmínky pro každý datový typ).
DLR je poskytováno pod Microsoft Permissive License, takže jsou k dispozici zdrojové kódy. Spolu s DLR Microsoft vydal také dva nové dynamické .NET jazyky - IronRuby a IronPython.
Navíc stejně jako DLR je i IronPython poskytován pod Microsoft Permissive License, takže i zdrojové kódy IronPythonu je možné stáhnout z Internetu a to z Codeplexu na adrese www.codeplex.com/IronPython ^ (zdrojové kódy DLR jsou součástí IronPythonu).
Dokumentace
Zatím nebyla vydána žádná oficiální dokumentace k DLR, většina dostupných informací jsou pouze příspěvky na blozích programátorů z Microsoftu a nebo uživatelů. Jako zdroj informací určitě poslouží zdrojové kódy IronPythonu, které jsou ale celkem rozsáhlé a navíc bez komentářů. Proto je k dispozici ještě implementace jazyka ToyScript, což je velice jednoduchý jazyk vyvinutý pouze pro „studijní“ účely. ToyScript je taktéž v repository IronPythonu (IronPython_Main/Src/ToyScript). Velice užitečný je dále blog Martina Malého z Microsoftu, jednoho z hlavních vývojářů DLR a také autora zmíněného ToyScriptu, jeho blog naleznete na adrese blogs.msdn.com/mmaly ^, kde zejména popisuje jak samotné DLR funguje.
Architektura kompilátorů
Ačkoliv programovací jazyky můžou být velice odlišné, architektura kompilátorů je často podobná. Kompilátor se většinou skládá ze tří částí - scaner, parser a generátor. Scaner má nastarost jako první rozdělit řetězec s kódem na jednotlivé tokeny (token je jednotka reprezentující klíčová slova, speciální znaky, hodnoty a pod). Parser z tokenů vytvoří stromovou strukturu označovanou jako abstract syntax tree (AST). Generátor posléze podle AST vygeneruje assembler nebo v případě .NET jazyků je generován CIL kód.
.NET kompilátor:

Co je abstract syntax tree (AST)?
AST je stromová struktura reprezentující kód, ve kterém hodnoty jsou listy (leafs), operace jsou uzly (nodes) a struktura stromu určuje v jakém pořadí mají být jednotlivé operace vykonány.
Zde je jednoduchý příklad “x = 3 * 2 - 4 / 2” a odpovídající AST:

Jednotlivé operace jsou vykonány rekurzivně, tzn. nejdříve 3 * 2 a 4 / 2, výsledky jsou odečteny a nakonec výsledná hodnota je přiřazena do proměnné x.

