Obsah
1. Programovací jazyk Clojure 17: využití standardních maker v praxi
5. Univerzální podmíněné provádění příkazů s využitím makra cond
6. Makro while další poněkud skrytá „nefunkcionální“ řídicí konstrukce
7. Makro dotimes: další příklad použití tail rekurze v praxi
8. Idiom with-* používaný v programovacích jazycích odvozených od LISPu
1. Programovací jazyk Clojure 17: využití maker v praxi
V dnešní části seriálu o programovacím jazyce Java i o virtuálním stroji Javy (JVM) dokončíme popis makrosystému jazyka Clojure postaveného nad JVM. V předchozích dvou částech tohoto seriálu jsme si řekli, jakým způsobem jsou makra aplikována (ještě před pokusem o vyhodnocení formy) a na několika demonstračních příkladech jsme si ukázali tvorbu vlastních uživatelských maker, při jejichž zápisu jsme používali takzvaná reader makra nazvaná „syntax-quote“ (zapisováno pomocí zpětného apostrofu), „unqote“ (zapisováno znakem tilda před symbolem) a „unquote-splicing“ (zapisováno znakem tilda následovaného zavináčem). Ovšem i přes možnost použití těchto znaků se speciálním významem je tvorba uživatelských maker poměrně složitá záležitost, protože jejich tvůrci musí zajistit správnou funkci makra i v různých mezních případech – makro je například zavoláno bez parametrů, jeho parametrem jsou jen prázdné závorky namísto očekávaného seznamu příkazů atd.
Nicméně makrosystém programovacího jazyka Clojure je možné využít i bez toho, aby musel vývojář vytvářet svá vlastní uživatelská makra – může totiž využít sadu maker dodávanou jako takřka nedílnou součást samotného Clojure. Některá dále popisovaná makra jsou totiž definována v souboru core.clj, jenž obsahuje definice zcela základních funkcí i maker, bez nichž by v podstatě nebylo možné prakticky používat smyčku REPL (teoreticky by to možné sice bylo, ale čitelnost takto vytvořených programů by nebyla vysoká). U všech dále popisovaných maker bude uvedena i jejich definice, protože právě na příkladu standardních maker se můžeme přiučit nejenom to, jak se mají vyvářet uživatelská makra, ale dozvíme se i základní informace o interní struktuře smyčky REPL. Taktéž si ukážeme některé idiomy používané v mnoha LISPovských programovacích jazycích (v samotném LISPu, Scheme atd.). Například se zmíníme o idiomu (Javisté by možná řekli „o návrhovém vzoru“) with-, jenž lze použít v mnoha místech aplikace, zejména tam, kde se pracuje s externím zdrojem (nebo naopak cílem) dat.
V navazujících kapitolách budou popsána následující standardní makra:
2. Makro comment
Jedno z nejjednodušších standardních maker definovaných v souboru core.clj se jmenuje comment. Jméno tohoto makra velmi přesně vystihuje, k čemu může být využíváno: do makra comment je totiž možné uzavřít prakticky libovolnou část programu, která bude makrem „sežrána“ (samozřejmě v čase načítání forem) a nebude tedy docházet k pokusu o vyhodnocení takto obaleného bloku. Jedinou podmínkou, kterou musí vývojář používající makro comment v každém případě dodržet, je nutnost vybalancování pravých a levých kulatých závorek v bloku, který je makrem comment obalen. Důvod je prostý – objekt reader totiž musí mít možnost určit, kde volání makra comment končí. Definice tohoto makra je skutečně velmi jednoduchá, protože makro comment očekává libovolné množství parametrů ([& body]), které nejsou žádným způsobem dále použity ani vyhodnocovány, protože tělo makra je prázdné:
; zdrojový kód makra comment (defmacro comment "Ignores body, yields nil" {:added "1.0"} [& body])
Na druhém řádku definice makra comment je zapsána dokumentace (obdoba Javadocu), na řádku třetím pak metadata o tom, kdy bylo toto makro do jazyka Clojure přidáno. Následuje příklad použití makra comment, který asi nepotřebuje další podrobnější vysvětlení:
; zakomentování formy user=> (comment (println "Hello world!")) nil ; expanze makra comment je vždy stejná: ; ... transformuje jakoukoli formu na nil user=> (macroexpand-1 '(comment (println "Hello world!"))) nil ; zakomentování volání jednoduché funkce user=> (comment (* (6 7))) nil ; zakomentovat lze i volání neexistující funkce ; ... nedojde k chybě, protože se vyhodnocení neuskuteční user=> (comment (foo 6 7)) nil ; pozor si musíme dát pouze na správné vybalancování závorek ; ... zde přebývá pravá složená závorka user=> (comment (println "Hello world!"))) nil RuntimeException Unmatched delimiter: ) clojure.lang.Util.runtimeException (Util.java:170) user=>
3. Makra when a when-not
Ve zdrojových kódech aplikací vytvářených v programovacím jazyce Clojure můžeme velmi často narazit na volání maker nazvaných when a when-not. Těmto makrům se předává podmínka zapsaná jako forma (tedy výraz) a poté tělo složené z libovolně dlouhé sekvence forem (příkazů). Obě makra se převedou na vyhodnocení prvního předaného výrazu s tím, že pokud je výraz vyhodnocen na hodnotu true u makra when či naopak na hodnotu false u makra when-not, budou zbývající výrazy vyhodnoceny v takovém pořadí, v jakém jsou zadány. Proč se však vlastně tato makra v praxi používají namísto přímého využití speciální formy if? Je to jednoduché – ve speciální formě if je možné uvést pouze jeden příkaz („tělo podmínky“) vyhodnocený jen tehdy, pokud je hodnota předané podmínky rovna true. Pokud programátor potřebuje uzavřít do podmínky větší množství příkazů, použije právě makra when a when-not, kde se tělo podmínky (seznam výrazů) automaticky uzavírá speciální formou do, která zajistí jejich sekvenční provedení. Navíc se při použití when-not vyhne případné nutnosti negování výrazu (podmínky):
; zdrojový kód makra when (defmacro when "Evaluates test. If logical true, evaluates body in an implicit do." {:added "1.0"} [test & body] (list 'if test (cons 'do body)))
; zdrojový kód makra when-not (defmacro when-not "Evaluates test. If logical false, evaluates body in an implicit do." {:added "1.0"} [test & body] (list 'if test nil (cons 'do body)))
Opět si ukážeme jednoduché příklady použití, včetně expanze maker:
; definice funkce, kterou v makrech when a when-not použijeme user=> (defn greater-than? [x y] (> x y)) #'user/greater-than?
; příklad použití makra when ; (povšimněte si, že návratovou hodnotou "do" ; je návratová hodnota posledního příkazu) user=> (when (greater-than? 2 1) (print 2) (print ">") (print 1)) 2>1nil ; expanze makra when vypadá následovně: user=> (macroexpand-1 '(when (greater-than? 2 1) (print 2) (print ">") (print 1))) (if (greater-than? 2 1) (do (print 2) (print ">") (print 1))) user=>
Makro when-not generuje výraz využívající speciální formu if se třemi parametry: podmínkou, „větví if“ a „větví else“, přičemž „větev if“ obsahuje prázdné tělo – hodnotu nil:
; příklad použití makra when-not user=> (when-not (greater-than? 2 1) (print 2) (print ">") (print 1)) nil ; expanze makra when-not ; (je zde patrné, že se jako druhý parametr speciální ; formy "if" předává vždy nil) user=> (macroexpand-1 '(when-not (greater-than? 2 1) (print 2) (print ">") (print 1))) (if (greater-than? 2 1) nil (do (print 2) (print ">") (print 1))) user=>
4. Makro if-not
Makra when a when-not popsaná v předchozí kapitole nejsou jedinými standardními makry, které do programovacího jazyka Clojure přidávají další řídicí konstrukce (alespoň z pohledu programátora). Dalším takovým dosti často používaným makrem je makro nazvané if-not, jehož význam je již ze samotného názvu tohoto makra zřejmý – jedná se o negaci funkcionality speciální formy if. Připomeňme si, že speciální formu if lze volat se dvěma či třemi parametry. Pokud je tato forma zavolána s dvojicí parametrů, je první parametr chápán jako podmínka a druhý parametr (jenž samozřejmě musí být platnou formou) je vyhodnocen pouze tehdy, pokud je první parametr vyhodnocen na true. V případě, že je speciální forma if zavolána se třemi parametry, slouží poslední parametr jako náhrada „větve else“, ovšem opět se musí jednat pouze o jediný výraz, což je omezení speciální formy if. Toto omezení se v praxi obchází využitím maker when a when-not (viz předchozí kapitolu).
Zatímco těla všech tří maker, s nimiž jsme se seznámili v předchozí dvojici kapitol, byla velmi jednoduchá, je tělo makra if-not již poněkud komplikovanější, a to ze dvou důvodů. První důvod spočívá v tom, že uživatel toto makro bude moci volat se dvěma či třemi parametry, tudíž je nutné vytvořit „multimakro“ s dvojicí těl (multimakro se zapisuje stejným způsobem jako multifunkce – pro každý počet parametrů je zapsáno zvláštní tělo funkce/makra). Druhý důvod větší složitosti makra if-not je způsoben použitím reader maker „syntax-quote“ (zpětný apostrof) a „unquote“ (tilda), díky nimž lze makro zapsat formou šablony, což je doporučovaný způsob zápisu maker, s nímž jsme se podrobněji seznámili v předchozí části tohoto seriálu:
; zdrojový kód makra if-not (defmacro if-not "Evaluates test. If logical false, evaluates and returns then expr, otherwise else expr, if supplied, else nil." {:added "1.0"} ([test then] `(if-not ~test ~then nil)) ([test then else] `(if (not ~test) ~then ~else)))
Dodejme jen, že test, then a else nejsou v tomto případě žádná klíčová slova, ale pouze názvy parametrů předávaných makru if-not při jeho volání (názvy parametrů nesmí být quotovány, proto jsou před nimi zapsány tildy).
Jednoduchý příklad použití tohoto makra:
user=> (if-not (zero? (- 1 1)) (println "nenulovy vysledek")) nil user=> (if-not (zero? (- 2 1)) (println "nenulovy vysledek")) nenulovy vysledek nil ; díky použití syntax-quote se rozepíše funkce not na plný název user=> (macroexpand '(if-not (zero? (- 2 1)) (println "nenulovy vysledek"))) (if (clojure.core/not (zero? (- 2 1))) (println "nenulovy vysledek") nil) user=>
5. Univerzální podmíněné provádění příkazů s využitím makra cond
Při popisu standardních maker jazyka Clojure nesmíme zapomenout na makro cond, které je nedílnou součástí mnoha programovacích jazyků odvozených od LISPu. Důvod pro tuto oblibu cond (ať již se jedná v konkrétní implementaci jazyka o makro či naopak o speciální formu) je prostý: v původním návrhu programovacího jazyka LISP byl tento jazyk kromě smyčky REPL doplněn o sedm základních funkcí a dvě speciální formy: atom, car, cdr, cond, cons, eq, quote, lambda a label.
Existence smyčky REPL a těchto sedmi speciálních forem/funkcí skutečně stačila pro vytvoření plnohodnotného (i když zpočátku ne příliš praktického) programovacího jazyka. V případě Clojure je situace vlastně zcela opačná, protože základní speciální formou používanou pro konstrukci podmínek, je speciální forma if, z níž je relativně snadné vytvořit makro cond. U některých implementací LISPu je tomu přesně naopak – základní speciální formou je zde cond a if je implementován jako makro.
Vraťme se však k makru cond použitém v programovacím jazyku Clojure. Toto makro akceptuje libovolný počet dvojic test-příkaz. Jednotlivé testy (jde samozřejmě o výrazy – formy) se postupně vyhodnocují a v případě, že se vyhodnotí na hodnotu true, vrátí makro cond hodnotu vyhodnoceného příkazu. V opačném případě se vyhodnotí další test atd. Pokud se ani jeden test nevyhodnotí na logickou hodnotu true, vrátí toto makro hodnotu nil. U makra cond je zajímavé prostudovat jeho stavbu, protože zde najdeme jak test na počet předávaných parametrů (musí být sudý, neboť jde vždy o dvojice test-příkaz), tak i rekurzi. Při rekurzivním volání makra se mu předají všechny původní parametry kromě prvních dvou (přesněji řečeno kromě první dvojice test-příkaz). Zkuste se sami zamyslet nad tím, kdy přesně k rekurzi dochází:
(defmacro cond "Takes a set of test/expr pairs. It evaluates each test one at a time. If a test returns logical true, cond evaluates and returns the value of the corresponding expr and doesn't evaluate any of the other tests or exprs. (cond) returns nil." {:added "1.0"} [& clauses] (when clauses (list 'if (first clauses) (if (next clauses) (second clauses) (throw (IllegalArgumentException. "cond requires an even number of forms"))) (cons 'clojure.core/cond (next (next clauses))))))
Na příkladu použití makra cond je patrné, že velmi efektivním způsobem dokáže nahradit jak příkaz switch-case, tak i sekvenci příkazů if-elseif-elseif-else, které se mnohdy nevyhneme v jiných programovacích jazycích. Zajímavé je zde i použití :else, což je keyword (ty se zapisují s dvojtečkou před symbolem). Využívá se zde faktu, že if :keyword … vždy povede k vyhodnocení těla speciální formy if; ovšem skalní LISPaři pravděpodobně v poslední větvi cond použijí namísto testu přímo hodnotu true (v LISPu jen T):
; definice funkce, v níž je využito makro cond (defn znamka [body] (cond (>= body 95) "A" (>= body 80) "B" (>= body 70) "C" (>= body 60) "D" (>= body 50) "E" :else "F")) ; test funkce znamka user=> (znamka 0) "F" ; test funkce znamka user=> (znamka 50) "E" ; test funkce znamka user=> (znamka 90) "B" ; test funkce znamka user=> (znamka 100) "A" ; složitější příklad user=> (map znamka (range 0 101 10)) ("F" "F" "F" "F" "F" "E" "D" "C" "B" "B" "A") user=>
6. Makro while další poněkud skrytá „nefunkcionální“ řídicí konstrukce
Dalším standardním makrem, o němž se v dnešním článku zmíníme, je makro nazvané while. Asi správně uhodnete, že toto makro iterativně spouští (či lépe řečeno postupně vyhodnocuje) nějaké tělo smyčky, a to tak dlouho, dokud platí, že výraz zapsaný za while se vyhodnotí na pravdivostní hodnotu true. Povšimněte si, že se opět tiše předpokládá, že tělo smyčky bude mít nějaký vedlejší efekt jenž způsobí změnu hodnoty výrazu smyčky while (nejedná se tedy z pohledu funkcionálního programátora o příliš šťastně vytvořenou konstrukci). Typickým vedlejším efektem je nastavení hodnoty nějaké lokální či globální proměnné. Pravděpodobně taktéž uhodnete, jak je makro while interně implementováno – musí se v něm použít rekurze a to dokonce tail rekurze, která je v programovacím jazyce Clojure představována dvojicí loop-recur. Jak loop tak i recur jsou speciální formy tvořící základní jazykové konstrukce využitelné programátorem:
; definice makra while (defmacro while "Repeatedly executes body while test expression is true. Presumes some side-effect will cause test to become false/nil. Returns nil" {:added "1.0"} [test & body] `(loop [] (when ~test ~@body (recur))))
Demonstrační příklad bude asi dosti netypický:
user=> (while (> (Math/random) 0.1) (println "Stale pocitam")) Stale pocitam Stale pocitam Stale pocitam Stale pocitam Stale pocitam Stale pocitam Stale pocitam Stale pocitam Stale pocitam nil user=>
Expanze výše vypsané „smyčky while“ vypadá takto:
user=> (macroexpand-1 '(while (> (Math/random) 0.1) (println "Stale pocitam"))) (clojure.core/loop [] (clojure.core/when (> (Math/random) 0.1) (println "Stale pocitam") (recur))) ; (výstup byl zarovnán ručně) user=>
7. Makro dotimes: další příklad použití tail rekurze v praxi
V některých typech aplikací může být poměrně užitečné použít makro nazvané jednoduše a přitom příhodně dotimes, které dokáže předaný výraz (formu) opakovat n krát. Přitom toto makro může v každé iteraci (opakování) nastavit zvolenou lokální proměnnou na aktuální hodnotu počitadla, přičemž se hodnota počitadla v první iteraci vždy nastavuje na nulu a v poslední iteraci dosahuje zadaného počtu opakování-1. Vzdáleně tedy můžeme toto makro považovat za ekvivalent programové smyčky for i in range(n): v programovacím jazyku Python či ekvivalent k počítané smyčce for (int i = 0; i<n; i++) známé z céčka (zde bez možnosti mít lokální proměnnou jako počitadlo), C++, Javy atd. Vzhledem k tomu, že se předpokládá, že forma – tělo smyčky – předaná makru dotimes bude mít nějaký vedlejší efekt, nejedná se sice o čistě funkcionální přístup, nicméně makro dotimes může být skutečně velmi užitečné, například při práci s poli (jejich použití v aplikaci je většinou diktováno snahou o dosažení větší efektivity programu).
; definice makra dotimes je na první pohled dosti komplikovaná ; (povšimněte si použití makra when uvnitř definice jiného makra) (defmacro dotimes "bindings => name n Repeatedly executes body (presumably for side-effects) with name bound to integers from 0 through n-1." {:added "1.0"} [bindings & body] ; kontroly (assert-args (vector? bindings) "a vector for its binding" (= 2 (count bindings)) "exactly 2 forms in binding vector") ; vlastní výkonné tělo makra ; využívající dvojici lokálních proměnných i a n (let [i (first bindings) n (second bindings)] `(let [n# (long ~n)] (loop [~i 0] (when (< ~i n#) ~@body (recur (unchecked-inc ~i)))))))
Příklad použití makra dotimes jsme si již v tomto seriálu ukazovali:
(dotimes [i 10] (dotimes [j 10] (print (* (inc i) (inc j)) "\t")) (println))
A zde je již výsledek práce tohoto skriptu (poslední nil je návratovou hodnotou makra dotimes):
1 2 3 4 5 6 7 8 9 10 2 4 6 8 10 12 14 16 18 20 3 6 9 12 15 18 21 24 27 30 4 8 12 16 20 24 28 32 36 40 5 10 15 20 25 30 35 40 45 50 6 12 18 24 30 36 42 48 54 60 7 14 21 28 35 42 49 56 63 70 8 16 24 32 40 48 56 64 72 80 9 18 27 36 45 54 63 72 81 90 10 20 30 40 50 60 70 80 90 100 nil
Na expanzi výrazu:
(dotimes [i 10] (println i))
je patrné použití lokálních symbolů s jedinečným jménem:
user=> (macroexpand-1 '(dotimes [i 10] (println i))) (clojure.core/let [n__4220__auto__ (clojure.core/long 10)] (clojure.core/loop [i 0] (clojure.core/when (clojure.core/< i n__4220__auto__) (println i) (recur (clojure.core/unchecked-inc i))))) ; (výstup byl zarovnán ručně) user=>
8. Idiom with-* používaný v programovacích jazycích odvozených od LISPu
Při tvorbě reálných aplikací v programovacím jazyku Clojure se poměrně často setkáme s následujícím problémem: máme za úkol otevřít nějaký zdroj dat (databázi, soubor…), přečíst z tohoto zdroje data a posléze zdroj dat opět zavřít. Dalším praktickým problémem je nastavení přesnosti a zaokrouhlovacího režimu pro objekty typu BigDecimal, provedení nějaké matematické operace a následně obnovení původní přesnosti a zaokrouhlovacího režimu. Všechny tyto problémy tedy vyžadují, aby se provedla nějaká nastavovací operace, která většinou mění prostředí programu, posléze se provede vlastní výpočet/sekvence příkazů a nakonec se obnoví původní prostředí programu. Takto chápané operace se v programovacím jazyce Clojure poměrně často implementují s využitím maker, jejichž název začíná na with-. Příkladem může být makro with-precision pro dočasnou změnu přesnosti a zaokrouhlovacího režimu pro objekty typu BigDecimal (viz předchozí text):
user=> (with-precision 1 (/ 1M 3)) 0.3M user=> (with-precision 2 (/ 1M 3)) 0.33M user=> (with-precision 10 (/ 1M 3)) 0.3333333333M user=>
Příkladem takto pojatého makra je poměrně užitečné standardní makro with-out-str, které dokáže „zachytit“ všechna volání funkcí print a println. Řetězce, které by se pomocí těchto funkcí normálně vypsaly na standardní výstup, jsou namísto využity jako návratová hodnota makra:
user=> (with-out-str (print "Hello ") (print "world") (print '!)) "Hello world!" user=> (def vystup (with-out-str (print "Hello ") (print "world") (print '!))) #'user/vystup user=> vystup "Hello world!" user=>
Jak již bylo řečeno v úvodním odstavci, pracují makra with- takovým způsobem, že dočasně změní prostředí programu. Nejinak je tomu i v případě makra with-out-str, kde se dočasně změní objekt navázaný na symbol *out*, jenž představuje standardní výstup, neboli v řeči Javy System.out. Symbol *out* je při provádění příkazů předaných makru přesměrován na novou instanci objektu java.io.StringWriter, který je po provedení těla převeden na řetězec s využitím funkce str:
(defmacro with-out-str "Evaluates exprs in a context in which *out* is bound to a fresh StringWriter. Returns the string created by any nested printing calls." {:added "1.0"} [& body] `(let [s# (new java.io.StringWriter)] (binding [*out* s#] ~@body (str s#))))
Jediným neznámým symbolem je zde binding, což je další makro, které dokáže dočasně (v rámci provádění těla) navázat na nějaký symbol jinou hodnotu.
9. Odkazy na Internetu
- Clojure Macro Tutorial (Part I, Getting the Compiler to Write Your Code For You)
http://www.learningclojure.com/2010/09/clojure-macro-tutorial-part-i-getting.html - Clojure Macro Tutorial (Part II: The Compiler Strikes Back)
http://www.learningclojure.com/2010/09/clojure-macro-tutorial-part-ii-compiler.html - Clojure Macro Tutorial (Part III: Syntax Quote)
http://www.learningclojure.com/2010/09/clojure-macro-tutorial-part-ii-syntax.html - Tech behind Tech: Clojure Macros Simplified
http://techbehindtech.com/2010/09/28/clojure-macros-simplified/ - Fatvat – Exploring functional programming: Clojure Macros
http://www.fatvat.co.uk/2009/02/clojure-macros.html - Eulerovo číslo
http://cs.wikipedia.org/wiki/Eulerovo_číslo - List comprehension
http://en.wikipedia.org/wiki/List_comprehension - List Comprehensions in Clojure
http://asymmetrical-view.com/2008/11/18/list-comprehensions-in-clojure.html - Clojure Programming Concepts: List Comprehension
http://en.wikibooks.org/wiki/Clojure_Programming/Concepts#List_Comprehension - Clojure core API: for macro
http://clojure.github.com/clojure/clojure.core-api.html#clojure.core/for - cirrus machina – The Clojure for macro
http://www.cirrusmachina.com/blog/comment/the-clojure-for-macro/ - Clojure.org: Clojure home page
http://clojure.org/downloads - Clojure.org: Vars and the Global Environment
http://clojure.org/Vars - Clojure.org: Refs and Transactions
http://clojure.org/Refs - Clojure.org: Atoms
http://clojure.org/Atoms - Clojure.org: Agents as Asynchronous Actions
http://clojure.org/agents - A Couple of Clojure Agent Examples
http://lethain.com/a-couple-of-clojure-agent-examples/ - Clojure – Functional Programming for the JVM
http://java.ociweb.com/mark/clojure/article.html - Clojure quick reference
http://faustus.webatu.com/clj-quick-ref.html - 4Clojure
http://www.4clojure.com/ - ClojureDoc
http://clojuredocs.org/ - Clojure (Wikipedia EN)
http://en.wikipedia.org/wiki/Clojure - Clojure (Wikipedia CS)
http://cs.wikipedia.org/wiki/Clojure - Riastradh's Lisp Style Rules
http://mumble.net/~campbell/scheme/style.txt - Dynamic Languages Strike Back
http://steve-yegge.blogspot.cz/2008/05/dynamic-languages-strike-back.html - Scripting: Higher Level Programming for the 21st Century
http://www.tcl.tk/doc/scripting.html - Java Virtual Machine Support for Non-Java Languages
http://docs.oracle.com/javase/7/docs/technotes/guides/vm/multiple-language-support.html - New JDK 7 Feature: Support for Dynamically Typed Languages in the Java Virtual Machine
http://java.sun.com/developer/technicalArticles/DynTypeLang/ - JSR 223: Scripting for the JavaTM Platform
http://jcp.org/en/jsr/detail?id=223 - JSR 292: Supporting Dynamically Typed Languages on the JavaTM Platform
http://jcp.org/en/jsr/detail?id=292 - Java 7: A complete invokedynamic example
http://niklasschlimm.blogspot.com/2012/02/java-7-complete-invokedynamic-example.html - InvokeDynamic: Actually Useful?
http://blog.headius.com/2007/01/invokedynamic-actually-useful.html - A First Taste of InvokeDynamic
http://blog.headius.com/2008/09/first-taste-of-invokedynamic.html - Java 6 try/finally compilation without jsr/ret
http://cliffhacks.blogspot.com/2008/02/java-6-tryfinally-compilation-without.html - An empirical study of Java bytecode programs
http://www.mendeley.com/research/an-empirical-study-of-java-bytecode-programs/ - Java quick guide: JVM Instruction Set (tabulka všech instrukcí JVM)
http://www.mobilefish.com/tutorials/java/java_quickguide_jvm_instruction_set.html - The JVM Instruction Set
http://mpdeboer.home.xs4all.nl/scriptie/node14.html - Control Flow in the Java Virtual Machine
http://www.artima.com/underthehood/flowP.html - Root.cz: Využití komprimovaných ukazatelů na objekty v JVM
http://www.root.cz/clanky/vyuziti-komprimovanych-ukazatelu-na-objekty-v-nbsp-jvm/ - Root.cz: JamVM aneb alternativa k HotSpotu nejenom pro embedded zařízení a chytré telefony
http://www.root.cz/clanky/jamvm-aneb-alternativa-k-hotspotu-nejenom-pro-embedded-zarizeni-tablety-a-chytre-telefony/ - The JavaTM Virtual Machine Specification, Second Edition
http://java.sun.com/docs/books/jvms/second_edition/html/VMSpecTOC.doc.html - The class File Format
http://java.sun.com/docs/books/jvms/second_edition/html/ClassFile.doc.html - javap – The Java Class File Disassembler
http://docs.oracle.com/javase/1.4.2/docs/tooldocs/windows/javap.html - javap-java-1.6.0-openjdk(1) – Linux man page
http://linux.die.net/man/1/javap-java-1.6.0-openjdk - Using javap
http://www.idevelopment.info/data/Programming/java/miscellaneous_java/Using_javap.html - Examine class files with the javap command
http://www.techrepublic.com/article/examine-class-files-with-the-javap-command/5815354 - BCEL Home page
http://commons.apache.org/bcel/ - BCEL Manual
http://commons.apache.org/bcel/manual.html - Byte Code Engineering Library (Wikipedia)
http://en.wikipedia.org/wiki/BCEL - Java programming dynamics, Part 7: Bytecode engineering with BCEL
http://www.ibm.com/developerworks/java/library/j-dyn0414/ - Bytecode Engineering
http://book.chinaunix.net/special/ebook/Core_Java2_Volume2AF/0131118269/ch13lev1sec6.html - BCEL Tutorial
http://www.smfsupport.com/support/java/bcel-tutorial!/ - ASM Home page
http://asm.ow2.org/ - Seznam nástrojů využívajících projekt ASM
http://asm.ow2.org/users.html - ObjectWeb ASM (Wikipedia)
http://en.wikipedia.org/wiki/ObjectWeb_ASM - Java Bytecode BCEL vs ASM
http://james.onegoodcookie.com/2005/10/26/java-bytecode-bcel-vs-asm/ - Bytecode Outline plugin for Eclipse (screenshoty + info)
http://asm.ow2.org/eclipse/index.html - aspectj (Eclipse)
http://www.eclipse.org/aspectj/ - Aspect-oriented programming (Wikipedia)
http://en.wikipedia.org/wiki/Aspect_oriented_programming - AspectJ (Wikipedia)
http://en.wikipedia.org/wiki/AspectJ - EMMA: a free Java code coverage tool
http://emma.sourceforge.net/ - Cobertura
http://cobertura.sourceforge.net/ - FindBugs
http://findbugs.sourceforge.net/ - GNU Classpath
www.gnu.org/s/classpath/ - Java VMs Compared
http://bugblogger.com/java-vms-compared-160/ - JSRs: Java Specification Requests – JSR 223: Scripting for the Java Platform
http://www.jcp.org/en/jsr/detail?id=223 - Scripting for the Java Platform
http://java.sun.com/developer/technicalArticles/J2SE/Desktop/scripting/ - Scripting for the Java Platform (Wikipedia)
http://en.wikipedia.org/wiki/Scripting_for_the_Java_Platform - Java Community Process
http://en.wikipedia.org/wiki/Java_Specification_Request - Java HotSpot VM Options
http://www.oracle.com/technetwork/java/javase/tech/vmoptions-jsp-140102.html - Great Computer Language Shootout
http://c2.com/cgi/wiki?GreatComputerLanguageShootout - Java performance
http://en.wikipedia.org/wiki/Java_performance - Trying the prototype
http://mail.openjdk.java.net/pipermail/lambda-dev/2010-August/002179.html - Better closures (for Java)
http://blogs.sun.com/jrose/entry/better_closures - Lambdas in Java: An In-Depth Analysis
http://www.infoq.com/articles/lambdas-java-analysis - Class ReflectiveOperationException
http://download.java.net/jdk7/docs/api/java/lang/ReflectiveOperationException.html - Scala Programming Language
http://www.scala-lang.org/ - Run Scala in Apache Tomcat in 10 minutes
http://www.softwaresecretweapons.com/jspwiki/run-scala-in-apache-tomcat-in-10-minutes - Fast Web Development With Scala
http://chasethedevil.blogspot.cz/2007/09/fast-web-development-with-scala.html - Top five scripting languages on the JVM
http://www.infoworld.com/d/developer-world/top-five-scripting-languages-the-jvm-855 - Proposal: Indexing access syntax for Lists and Maps
http://mail.openjdk.java.net/pipermail/coin-dev/2009-March/001108.html - Proposal: Elvis and Other Null-Safe Operators
http://mail.openjdk.java.net/pipermail/coin-dev/2009-March/000047.html - Java 7 : Oracle pushes a first version of closures
http://www.baptiste-wicht.com/2010/05/oracle-pushes-a-first-version-of-closures/ - Groovy: An agile dynamic language for the Java Platform
http://groovy.codehaus.org/Operators - Better Strategies for Null Handling in Java
http://www.slideshare.net/Stephan.Schmidt/better-strategies-for-null-handling-in-java - Control Flow in the Java Virtual Machine
http://www.artima.com/underthehood/flowP.html - Java Virtual Machine
http://en.wikipedia.org/wiki/Java_virtual_machine - ==, .equals(), compareTo(), and compare()
http://leepoint.net/notes-java/data/expressions/22compareobjects.html - New JDK7 features
http://openjdk.java.net/projects/jdk7/features/ - Project Coin: Bringing it to a Close(able)
http://blogs.sun.com/darcy/entry/project_coin_bring_close - CloseableFinder source code
http://blogs.sun.com/darcy/resource/ProjectCoin/CloseableFinder.java - Joe Darcy blog about JDK
http://blogs.sun.com/darcy - Java 7 – more dynamics
http://www.baptiste-wicht.com/2010/04/java-7-more-dynamics/ - New JDK 7 Feature: Support for Dynamically Typed Languages in the Java Virtual Machine
http://java.sun.com/developer/technicalArticles/DynTypeLang/index.html