Obsah
1. Programovací jazyk Clojure 8: identity, stavy, neměnné hodnoty a referenční typy
2. Čtyři typy referencí podporovaných programovacím jazykem Clojure
3. Způsoby vytvoření všech čtyř typů referencí
3.1 Vytvoření reference typu „var“
3.2 Vytvoření reference typu „ref“
3.3 Vytvoření reference typu „atom“
3.4 Vytvoření reference typu „agent“
8. Čekání na dokončení akce poslané agentovi
1. Programovací jazyk Clojure 8: identity, stavy, neměnné hodnoty a referenční typy
V předchozích dvou částech [1][2] tohoto seriálu jsme se seznámili s některými technologiemi poskytovanými programovacím jazykem Clojure, které slouží k usnadnění tvorby vícevláknových programů. Připomeňme si, že se v prvé řadě jednalo o trojici funkcí/maker pmap, pcalls a pvalues, které je možné použít pro explicitní spuštění několika výpočtů prováděných paralelně. Dále jsme se pak zabývali objekty typu future a promise sloužícími taktéž ke spouštění výpočtů v samostatných vláknech. Následně jsme si popsali technologii STM – Software Transactional Memory, jenž umožňuje „zapouzdřit“ určitou sekvenci příkazů do transakce reprezentované funkcí dosync, která se provede z pohledu ostatních vláken atomicky (resp. tak, že jsou zajištěny vlastnosti ACID).
Ovšem tvůrci programovacího jazyka Clojure, zejména pak jeho hlavní vývojář a současně i zakladatel tohoto projektu Rich Hickey, si byli vědomi toho, že při tvorbě paralelních programů je mnohdy nutné využít větší množství různých přístupů k vývoji vícevláknových aplikací, které se od sebe liší především ve způsobu, jakým se mění stav sdílených objektů, neboli identit (v Clojure se pojmem stav označují hodnoty libovolného neměnitelného – immutable – datového typu, například čísla, pravdivostní hodnoty, seznamu, vektoru, mapy či množiny). Změna stavů více identit totiž může být provedena buď koordinovaně či naopak zcela nezávisle na ostatních identitách. Koordinovaná změna stavu více identit je prováděna uvnitř transakcí popsaných minule, tj. s využitím objektů typu ref. Mimochodem: slovem ref se v Clojure označuje jeden ze čtyř typů „referencí“, ovšem samotný pojem „reference“ má v programovacím jazyku Clojure odlišný význam, než je tomu v Javě či podobných programovacích jazycích. V jazyku Clojure totiž reference vždy ukazuje na neměnná data (již zmíněné numerické hodnoty, seznamy, množiny atd.).
Změna, resp. změny stavů identit se taktéž odlišují v tom, že mohou být provedeny buď synchronně či asynchronně – opět v závislosti na potřebách konkrétní vyvíjené aplikace. Synchronní změna stavu identit je provedena ihned a tudíž přímo ve vláknu, které tuto změnu provádí (synchronní a současně i nezávislá změna stavu identity je tedy z hlediska vývojáře prakticky totožná se změnou hodnoty proměnné). Naopak asynchronní změna stavu identit(y) nemusí být provedena ihned, ale někdy v blíže neurčené budoucnosti. To znamená, že asynchronní změnu je možné implementovat v jiném vlákně. Použití asynchronních změn je jedním z nejjednodušších způsobů využití více vláken ve vyvíjených aplikacích, což jsme si již ostatně ukázali na příkladu objektů typu future a promise. Jak uvidíme v dalších kapitolách, používají se pro implementaci asynchronně probíhajících výpočtů i takzvaní agenti (agents).
2. Čtyři typy referencí podporovaných programovacím jazykem Clojure
V předchozí kapitole jsme si řekli, že v programovacím jazyce Clojure existují čtyři typy referencí, přesněji řečeno čtyři takzvané referenční typy. Reference vždy ukazují na neměnná data, protože filozofie jazyka Clojure je založena nikoli na jednoduché změně obsahu proměnných (či změně stavu objektů – tj. jejich atributů, pokud budeme uvažovat i o objektově orientovaných jazycích), ale na takzvaných identitách asociovaných s různými stavy, které se v různých časových okamžicích běžícího programu mohou lišit. Samotný stav je představován neměnnou (immutable) hodnotou, což však neznamená, že by reference po celou dobu běhu programu musela odkazovat na stejný stav. Reference totiž může být přesměrována na jinou neměnnou hodnotu – zkráceně budeme říkat, že se změnila hodnota reference, i když je to poněkud nepřesné. Zmíněné čtyři typy referencí použitých v programovacím jazyku Clojure se od sebe odlišují především v tom, zda je změna hodnot referencí synchronní či asynchronní a zda je realizována koordinovaně (tj. v transakci) či nezávisle na změně hodnot ostatních referencí.
Všechny čtyři podporované referenční typy jsou vypsány v následující tabulce:
Jméno | Var | Ref | Atom | Agent |
---|---|---|---|---|
Změna stavu | synchronní | synchronní | synchronní | asynchronní |
Typ změny | lokální, v rámci jednoho vlákna | koordinovaná | nezávislá | nezávislá |
Podpora transakcí | ne | ano | ne | ne |
3. Způsoby vytvoření všech čtyř typů referencí
Kromě prvního typu reference (var) je nutné u dalších třech typů referencí pro přečtení stavu identity, s níž je tato reference svázána, použít funkci deref, popř. namísto této funkce využít makro preprocesoru zapisované pomocí zavináče @. Nutnost použití funkce deref namísto přímého čtení hodnoty vychází z toho, že se například v případě agentů musí provést synchronizace vláken, popř. je nutné zajistit atomičnost čtení/změny hodnoty atd. Každý typ reference se vytváří pomocí jiné funkce, z nichž každá je popsána ve zvláštní podkapitole:
3.1 Vytvoření reference typu „var“
Při vytváření reference typu var se specifikuje jak jméno reference, tak i (i když nepovinně) její počáteční hodnota. Pro tento účel se používá nám již známá speciální forma def:
(def jméno počáteční_hodnota)
3.2 Vytvoření reference typu „ref“
Pro vytvoření reference typu ref se používá funkce ref. Povšimněte si však, že se nikde nepředává jméno vytvořené reference – přiřazení ke jménu je totiž již záležitostí programátora:
(ref počáteční_hodnota)
Příklad vytvoření reference s navázáním na symbol (jméno):
(def account-1 (ref 10000))
3.3 Vytvoření reference typu „atom“
Vytvoření reference typu atom je v mnoha ohledech podobné vytvoření předešlého typu reference:
(atom počáteční_hodnota)
Pokud je zapotřebí navázat referenci na symbol (což zapotřebí skutečně bývá), používá se tento idiom:
(def answer (atom 42))
3.4 Vytvoření reference typu „agent“
Posledním podporovaným typem referencí jsou takzvaní agenti, již se vytváří s využitím funkce agent:
(agent počáteční_hodnota)
I v případě agentů je někdy žádoucí je navázat na symbol:
(def agent007 (agent 7))
4. Referenční typ „Var“
Vývojářům, kteří kromě Clojure znají i jiný (imperativní či funkcionální) programovací jazyk, bude první typ referencí – var(s) – připadat povědomý, protože práce s tímto referenčním typem se nejvíce přibližuje způsobu práce s běžnými proměnnými (i když je obecně bezpečnější používat spíše atomy, popsané v dalším textu). Jak jsme si již řekli v předchozí kapitole, vytváří se nová reference typu var s využitím speciální formy def, které se předá jak jméno reference, tak i její počáteční hodnota: (def jméno hodnota). Alternativně je možné referenci pouze vytvořit a nepřiřadit jí žádnou počáteční hodnotu: (def jméno). Programovací jazyk Clojure samozřejmě při každém pokusu o přístup k hodnotě přiřazené k referenci kontroluje, zda tato hodnota existuje, či nikoli, a v případě pokusu o přečtení neinicializované reference dojde k chybě. Podívejme se na jednoduchý demonstrační příklad, v němž budou vytvořeny dvě reference typu var:
; vytvoření první reference, která však ; není navázána na žádnou hodnotu user=> (def foo) #'user/foo ; vytvoření druhé reference, která je ; navázána na (neměnitelnou) hodnotu 42 user=> (def bar 42) #'user/bar ; pokus o přístup k hodnotě navázané ; na první referenci user=> foo #<Unbound Unbound: #'user/foo> ; pokus o přístup k hodnotě navázané ; na druhou referenci user=> bar 42
Reference vytvořené s využitím speciální formy def (bez použití dalších metadat) můžeme považovat za statické globální proměnné, a právě takovým způsobem jsme s nimi vlastně už pracovali:
user=> (def x 2) #'user/x user=> (def y 3) #'user/y user=> (+ x y) 5 user=> (* (+ x y) (- x y)) -5
Reference typu var lze pomocí dalšího volání def změnit tak, aby ukazovaly na jinou neměnitelnou hodnotu:
user=> (def foo 10) #'user/foo user=> foo 10 user=> (def foo [1 2 3 4]) #'user/foo user=> foo [1 2 3 4]
Zatímco reference vytvořené s využitím speciální formy def jsou globální a tudíž i sdílené mezi vlákny, je možné vytvořit i lokální „proměnnou“, a to s využitím speciální formy nazvané let. V této formě je možné deklarovat obdobu „lokálních proměnných“ obsahujících opět neměnitelné hodnoty a navíc taktéž sekvenci výrazů, v nichž se mohou tyto „lokální proměnné“ použít:
; uvnitř speciální formy let lze využít ; lokální reference pojmenované local-y a local-y user=> (let [local-x 6 local-y 7] (* local-x local-y)) 42 ; pokus o přístup k oběma referencím ; mimo "let" skončí neúspěchem: user=> local-x CompilerException java.lang.RuntimeException: Unable to resolve symbol: local-x in this context, compiling:(NO_SOURCE_PATH:0)
Speciální forma let se využívá pro zjednodušení zápisu funkcí, kdy je možné výsledek nějakého mezivýpočtu svázat s lokálně viditelnou referencí a tím ho vlastně pojmenovat:
; výpočet průměru všech hodnot ; uložených ve vektoru ; (neoptimalizovaná verze výpočtu) (defn average [vektor] (let [ vector-size (count vektor) suma (reduce + vektor) ] (/ suma vector-size))) user=> (average [1 2 3 4]) 5/2
5. Referenční typ „Ref“
S referenčním typem ref jsme se již setkali v předcházející části tohoto seriálu. S využitím tohoto referenčního typu je možné vytvořit a používat identity, jejichž stav se mění synchronně (tj. ihned a přímo ve vláknu, v němž je funkce pro změnu stavu identit zavolána) a současně i koordinovaně. Aby byly obě tyto vlastnosti skutečně zaručeny, musí se funkce měnící stav identit, na niž odkazuje reference typu ref, volat uvnitř transakce, tj. uvnitř makra dosync – to je ostatně kontrolováno při běhu programu. Při čtení stavu identity, na niž je reference vázána, se používá funkce deref, popřípadě makro preprocesoru @. Změna stavu – volaná v transakci – se provádí s využitím funkcí ref-set a alter. Demonstrační příklad, v němž jsou použity tři reference typu ref, jsme si ukazovali minule, ale pro úplnost si ho můžeme zopakovat:
; vytvoření tří globálních symbolů ; navázaných na trojici referencí typu ref (def account-1 (ref 10000)) (def account-2 (ref 20000)) (def account-3 (ref 0)) ; pomocná funkce, která vytiskne aktuální ; stav identit, na něž jsou navázány tři ; reference (defn print-accounts [] (println "Account 1 : " @account-1) (println "Account 2 : " @account-2) (println "Account 3 : " @account-3)) ; funkce, v níž se *v transakci* ; mění stav identit (defn transfer-money [from to amount] (dosync (alter from - amount) (alter to + amount))) ; výpis hodnot před provedením transakce (println "Before transactions: ") (print-accounts) Before transactions: Account 1 : 10000 Account 2 : 20000 Account 3 : 0 nil ; provedení dvojice transakcí, z nichž ; každá splňuje ACID (transfer-money account-1 account-2 1000) (transfer-money account-2 account-3 10000) ; výpis hodnot po provedení transakce (println "After transactions: ") (print-accounts) After transactions: Account 1 : 9000 Account 2 : 11000 Account 3 : 10000 nil ; změna stavu identity mimo transakci ; není možná user=> (ref-set account-1 0) IllegalStateException No transaction running clojure.lang.LockingTransaction.getEx (LockingTransaction.java:208) ; je proto nutné veškerou změnu stavu ; provádět v makru dosync user=> (dosync (ref-set account-1 0)) 0
Programátor si však musí dát pozor na to, aby uvnitř transakce nevolal funkce s vedlejším efektem, protože v případě kolize může být transakce vykonána i několikrát. V následujícím příkladu je volána funkce s vedlejším efektem, což znamená, že by se mohl řetězec informující o prováděném součtu vypsat vícekrát, což asi není fatální, ale v případě zápisu do souboru atd. by to již mohlo vadit:
(defn myplus [x y] (println "scitam" x "a" y) (+ x y)) (dosync (alter account-1 myplus 10)) scitam 10 a 10 20
6. Referenční typ „Atom“
Zatímco s referenčními typy var a ref jsme se již setkali v předchozích částech tohoto seriálu, referenční typ pojmenovaný atom je pro nás (prozatím) novým pojmem. Změna stavu identit referencovaných přes atom se provádí synchronně, tj. podobně, jako tomu bylo u referenčního typu ref. Ovšem zatímco se u referenčního typu ref veškeré změny stavu identit prováděly v transakci (kde se mohlo nacházet libovolné množství výrazů – typicky výrazy pracující s více identitami), je u atomů změna jejich hodnoty provedena atomicky a nezávisle – ostatní vlákna tedy ihned budou pracovat s novou hodnotou. Práce s atomy je sice obecně efektivnější, než s ref, protože podpora transakcí není úplně zadarmo, ovšem pokud bychom se snažili demonstrační příklad uvedený v předchozí kapitole implementovat s využitím atomů, nebyla by zaručena konzistence dat při odečtení částky z prvního účtu a před přičtením této částky k účtu druhému.
Práce s atomy je v praxi velmi jednoduchá, protože si programátor vystačí se čtveřicí funkcí, k nimž můžeme připočíst ještě jedno makro preprocesoru. Všechny čtyři zmíněné funkce můžeme nalézt v následující tabulce:
# | Funkce | Význam |
---|---|---|
1 | atom | vytvoření reference typu atom |
2 | deref | dereference, vrátí se stav identity |
3 | reset! | atomická změna stavu identity na zvolenou hodnotu |
4 | swap! | atomická změna stavu identity zavoláním zvolené funkce |
; vytvoření nového atomu user=> (def x (atom 42)) #'user/x ; globální symbol x je navázán ; na atom a nikoli na stav identity ; (=hodnotu) user=> x #<Atom@61a907: 42> ; pro získání aktuálního stavu ; je nutné použít dereferenci user=> (deref x) 42 ; namísto (deref x) se používá ; makro preprocesoru @ user=> @x 42 ; atomická změna stavu identity user=> (reset! x 10) 10 user=> (reset! x (+ 1 2 3)) 6 user=> @x 6 ; další možnost atomické změny ; stavu identity - nyní přes funkci ; aplikovanou na atom a popř. i další ; parametry user=> (swap! x + 1) 7 user=> @x 7
K těmto čtyřem funkcím můžeme přidat ještě nízkoúrovňovou funkci pojmenovanou příznačně compare-and-set! (odvozeno od atomické operace test-and-set), která nastaví nový stav identity pouze za předpokladu, že se její stará hodnota rovná hodnotě předané do compare-and-set!. Na rozdíl od funkcí reset! a swap!, jejichž návratová hodnota odpovídá novému stavu identity, je návratová hodnota funkce compare-and-set! rovna true či false podle toho, jak porovnání (a tím pádem i nastavení) dopadlo:
user=> (compare-and-set! x 42 0) false user=> @x 7 user=> (compare-and-set! x 7 0) true user=> @x 0
7. Referenční typ „Agent“
Čtvrtý referenční typ, který nese název agent, je z hlediska programátora pravděpodobně nejzajímavější a v mnoha ohledech, především s ohledem na tvorbu vícevláknových aplikací, i nejužitečnější. S využitím agentů je totiž možné volat asynchronně prováděné funkce, které při svém vyhodnocení běží v samostatných vláknech získaných z poolu (vlákna tedy nemusí být neustále znovu vytvářena). Již na první pohled se tedy agenti podobají objektům typu future, s nimiž jsme se již v tomto seriálu setkali, ovšem nesmíme zapomínat na to, že objekty future sloužily k asynchronnímu spuštění prakticky libovolných výpočtů, zatímco agenti jsou skutečným referenčním typem navázaným na nějakou identitu a její stav. Agenti totiž nejenže asynchronně vykonají nějaký výpočet, ale současně i změní stav „své“ identity na základě výsledku tohoto výpočtu. To by zajisté bylo možné zařídit i s využitím future/promise, ale proč to dělat zbytečně komplikovaně, když je použití agentů velmi elegantní a současně se jedná o techniku, která se začíná těšit určité oblibě i mimo programovací jazyk Clojure?
V následující tabulce je vypsána čtveřice základních funkcí používaných pro práci s agenty:
# | Funkce | Význam |
---|---|---|
1 | agent | vytvoření reference typu agent |
2 | deref | dereference, vrátí se stav identity |
3 | send | poslání akce agentovi (libovolné funkce) |
3 | send-off | poslání akce agentovi (libovolné funkce) |
Rozdíl mezi funkcemi send a send-off spočívá v tom, že první z těchto funkcí by se měla používat pro spuštění náročnějších výpočtů, zatímco funkce druhá spíše pro operace, které budou blokující a nebo budou pracovat s I/O systémem. Pokud se vybere „špatná“ funkce, bude se program chovat stále korektně, ovšem využití vláken plánovačem nemusí být optimální.
Jednoduchý demonstrační příklad na použití agentů:
; vytvoření agenta user=> (def my-agent (agent 0)) #'user/my-agent ; poslání funkce agentovi (6 je druhý parametr funkce) user=> (send my-agent + 6) #<Agent@18622f3: 0> ; poslání funkce agentovi (7 je druhý parametr funkce) user=> (send my-agent * 7) #<Agent@18622f3: 6> ; dereference - získání nového stavu user=> @my-agent 42
Vidíme, že návratová hodnota funkcí + či * se stala novým stavem přiřazeným k identitě, na níž je agent navázán.
8. Čekání na dokončení akce poslané agentovi
Demonstrační příklad ukázaný v závěru předchozí kapitoly zdánlivě pracoval bez chyby, protože jsme pomocí @my-agent získali vždy novou hodnotu přiřazenou agentovi. Ve skutečnosti však již víme, že akce poslané agentovi (tj. předané funkce) se provádí v samostatných vláknech a nemusí být tedy při dereferencování ještě dokončeny. V tomto případě se při dereferenci jednoduše vrátí starý stav agenta. Můžeme si to ukázat na jednoduchém příkladu, v němž se agentovi pošle akce – funkce, která změní jeho hodnotu za přibližně deset sekund, tj. za dobu, která člověku stačí k tomu, aby ve smyčce REPL několikrát spustil dereferencování stavu agenta:
; definice funkce pro "pomalé" sčítání user=> (defn slow-inc [x] (Thread/sleep 10000) (inc x)) #'user/slow-inc ; vytvoření nového agenta user=> (def x (agent 0)) #'user/x ; zaslání akce agentovi user=> (send x slow-inc) #<Agent@32060c: 0> ; dereferencování user=> @x 0 user=> @x 0 user=> @x 0 user=> @x 0 user=> @x 0 ; teprve po přibližně deseti sekundách se konečně ; změnil stav identity user=> @x 1
Pro aktivní čekání na dokončení akce poslané jednomu agentovi či více agentům se používá dvojice funkcí:
# | Funkce | Význam |
---|---|---|
1 | await | čekání na dokončení akce poslané jednomu či více agentům |
2 | await-for | dtto, ale lze specifikovat i timeout |
První funkce nazvaná await umožňuje čekat na dokončení akce více agenty, ovšem toto čekání není shora nijak omezeno. V některých případech je tudíž užitečnější použít druhou funkci await-for, které se navíc předá i hodnota timeoutu zadaná v milisekundách. To, zda došlo k timeoutu, je možné zjistit z návratové hodnoty funkce await-for (true/false).
Příklad použití funkce await:
; definice funkce pro "pomalé" sčítání user=> (defn slow-inc [x] (Thread/sleep 10000) (inc x)) #'user/slow-inc ; vytvoření prvního agenta user=> (def agent1 (agent 0)) #'user/agent1 ; vytvoření druhého agenta user=> (def agent2 (agent 0)) #'user/agent2
; poslání dlouhotrvající akce prvnímu agentu user=> (send agent1 slow-inc) #<Agent@1efb4be: 0> ; poslání dlouhotrvající akce druhému agentu user=> (send agent2 slow-inc) #<Agent@5976c2: 0> ; ihned přečteme hodnotu obou agentů user=> @agent1 0 user=> @agent2 0
; blokující čekání na dokončení akcí (await agent1 agent2) nil ; ihned poté přečteme hodnotu obou agentů user=> @agent1 1 user=> @agent2 1
Příklad na použití funkce await-for
; definice funkce pro "pomalé" sčítání user=> (defn slow-inc [x] (Thread/sleep 10000) (inc x)) #'user/slow-inc ; vytvoření prvního agenta user=> (def agent1 (agent 0)) #'user/agent1 ; vytvoření druhého agenta user=> (def agent2 (agent 0)) #'user/agent2
; poslání dlouhotrvající akce prvnímu agentu user=> (send agent1 slow-inc) #<Agent@1efb4be: 0> ; poslání dlouhotrvající akce druhému agentu user=> (send agent2 slow-inc) #<Agent@5976c2: 0>
; čekáme na dokončení akce - ale pouze sekundu! user=> (await-for 1000 agent1 agent2) false ; stav agentů se za jednu sekundu ještě nezměnil user=> @agent1 0 user=> @agent2 0
9. Odkazy na Internetu
- 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