Programovací jazyk Clojure 8: identity, stavy, neměnné hodnoty a referenční typy

Pavel Tišnovský 31. 7. 2012

Dnes se budeme zabývat způsobem reprezentace stavu aplikace v programovacím jazyce Clojure i technikami, které se mohou použít pro změnu tohoto stavu. V Clojure se totiž pro uložení stavu aplikace nepoužívají běžné proměnné ani atributy objektů, ale takzvané referenční typy (zkráceně reference).

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“

4. Referenční typ „Var“

5. Referenční typ „Ref“

6. Referenční typ „Atom“

7. Referenční typ „Agent“

8. Čekání na dokončení akce poslané agentovi

9. Odkazy na Internetu

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).

widgety

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

  1. Clojure.org: Clojure home page
    http://clojure.org/downloads
  2. Clojure.org: Vars and the Global Environment
    http://clojure.org/Vars
  3. Clojure.org: Refs and Transactions
    http://clojure.org/Refs
  4. Clojure.org: Atoms
    http://clojure.org/Atoms
  5. Clojure.org: Agents as Asynchronous Actions
    http://clojure.org/agents
  6. A Couple of Clojure Agent Examples
    http://lethain.com/a-couple-of-clojure-agent-examples/
  7. Clojure – Functional Programming for the JVM
    http://java.ociweb.com/mar­k/clojure/article.html
  8. Clojure quick reference
    http://faustus.webatu.com/clj-quick-ref.html
  9. 4Clojure
    http://www.4clojure.com/
  10. ClojureDoc
    http://clojuredocs.org/
  11. Clojure (Wikipedia EN)
    http://en.wikipedia.org/wiki/Clojure
  12. Clojure (Wikipedia CS)
    http://cs.wikipedia.org/wiki/Clojure
  13. Riastradh's Lisp Style Rules
    http://mumble.net/~campbe­ll/scheme/style.txt
  14. Dynamic Languages Strike Back
    http://steve-yegge.blogspot.cz/2008/05/dynamic-languages-strike-back.html
  15. Scripting: Higher Level Programming for the 21st Century
    http://www.tcl.tk/doc/scripting.html
  16. Java Virtual Machine Support for Non-Java Languages
    http://docs.oracle.com/ja­vase/7/docs/technotes/gui­des/vm/multiple-language-support.html
  17. New JDK 7 Feature: Support for Dynamically Typed Languages in the Java Virtual Machine
    http://java.sun.com/develo­per/technicalArticles/Dyn­TypeLang/
  18. JSR 223: Scripting for the JavaTM Platform
    http://jcp.org/en/jsr/detail?id=223
  19. JSR 292: Supporting Dynamically Typed Languages on the JavaTM Platform
    http://jcp.org/en/jsr/detail?id=292
  20. Java 7: A complete invokedynamic example
    http://niklasschlimm.blog­spot.com/2012/02/java-7-complete-invokedynamic-example.html
  21. InvokeDynamic: Actually Useful?
    http://blog.headius.com/2007/01/in­vokedynamic-actually-useful.html
  22. A First Taste of InvokeDynamic
    http://blog.headius.com/2008/09/first-taste-of-invokedynamic.html
  23. Java 6 try/finally compilation without jsr/ret
    http://cliffhacks.blogspot­.com/2008/02/java-6-tryfinally-compilation-without.html
  24. An empirical study of Java bytecode programs
    http://www.mendeley.com/research/an-empirical-study-of-java-bytecode-programs/
  25. Java quick guide: JVM Instruction Set (tabulka všech instrukcí JVM)
    http://www.mobilefish.com/tu­torials/java/java_quickgu­ide_jvm_instruction_set.html
  26. The JVM Instruction Set
    http://mpdeboer.home.xs4a­ll.nl/scriptie/node14.html
  27. Control Flow in the Java Virtual Machine
    http://www.artima.com/under­thehood/flowP.html
  28. Root.cz: Využití komprimovaných ukazatelů na objekty v JVM
    http://www.root.cz/clanky/vyuziti-komprimovanych-ukazatelu-na-objekty-v-nbsp-jvm/
  29. 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/
  30. The JavaTM Virtual Machine Specification, Second Edition
    http://java.sun.com/docs/bo­oks/jvms/second_edition/html/VMSpec­TOC.doc.html
  31. The class File Format
    http://java.sun.com/docs/bo­oks/jvms/second_edition/html/Clas­sFile.doc.html
  32. javap – The Java Class File Disassembler
    http://docs.oracle.com/ja­vase/1.4.2/docs/tooldocs/win­dows/javap.html
  33. javap-java-1.6.0-openjdk(1) – Linux man page
    http://linux.die.net/man/1/javap-java-1.6.0-openjdk
  34. Using javap
    http://www.idevelopment.in­fo/data/Programming/java/mis­cellaneous_java/Using_javap­.html
  35. Examine class files with the javap command
    http://www.techrepublic.com/ar­ticle/examine-class-files-with-the-javap-command/5815354
  36. BCEL Home page
    http://commons.apache.org/bcel/
  37. BCEL Manual
    http://commons.apache.org/bcel/ma­nual.html
  38. Byte Code Engineering Library (Wikipedia)
    http://en.wikipedia.org/wiki/BCEL
  39. Java programming dynamics, Part 7: Bytecode engineering with BCEL
    http://www.ibm.com/develo­perworks/java/library/j-dyn0414/
  40. Bytecode Engineering
    http://book.chinaunix.net/spe­cial/ebook/Core_Java2_Volu­me2AF/0131118269/ch13lev1sec6­.html
  41. BCEL Tutorial
    http://www.smfsupport.com/sup­port/java/bcel-tutorial!/
  42. ASM Home page
    http://asm.ow2.org/
  43. Seznam nástrojů využívajících projekt ASM
    http://asm.ow2.org/users.html
  44. ObjectWeb ASM (Wikipedia)
    http://en.wikipedia.org/wi­ki/ObjectWeb_ASM
  45. Java Bytecode BCEL vs ASM
    http://james.onegoodcooki­e.com/2005/10/26/java-bytecode-bcel-vs-asm/
  46. Bytecode Outline plugin for Eclipse (screenshoty + info)
    http://asm.ow2.org/eclipse/index.html
  47. aspectj (Eclipse)
    http://www.eclipse.org/aspectj/
  48. Aspect-oriented programming (Wikipedia)
    http://en.wikipedia.org/wi­ki/Aspect_oriented_program­ming
  49. AspectJ (Wikipedia)
    http://en.wikipedia.org/wiki/AspectJ
  50. EMMA: a free Java code coverage tool
    http://emma.sourceforge.net/
  51. Cobertura
    http://cobertura.sourceforge.net/
  52. FindBugs
    http://findbugs.sourceforge.net/
  53. GNU Classpath
    www.gnu.org/s/classpath/
  54. Java VMs Compared
    http://bugblogger.com/java-vms-compared-160/
  55. JSRs: Java Specification Requests – JSR 223: Scripting for the Java Platform
    http://www.jcp.org/en/jsr/de­tail?id=223
  56. Scripting for the Java Platform
    http://java.sun.com/develo­per/technicalArticles/J2SE/Des­ktop/scripting/
  57. Scripting for the Java Platform (Wikipedia)
    http://en.wikipedia.org/wi­ki/Scripting_for_the_Java_Plat­form
  58. Java Community Process
    http://en.wikipedia.org/wi­ki/Java_Specification_Requ­est
  59. Java HotSpot VM Options
    http://www.oracle.com/technet­work/java/javase/tech/vmop­tions-jsp-140102.html
  60. Great Computer Language Shootout
    http://c2.com/cgi/wiki?Gre­atComputerLanguageShootout
  61. Java performance
    http://en.wikipedia.org/wi­ki/Java_performance
  62. Trying the prototype
    http://mail.openjdk.java.net/pi­permail/lambda-dev/2010-August/002179.html
  63. Better closures (for Java)
    http://blogs.sun.com/jrose/en­try/better_closures
  64. Lambdas in Java: An In-Depth Analysis
    http://www.infoq.com/articles/lambdas-java-analysis
  65. Class ReflectiveOperationException
    http://download.java.net/jdk7/doc­s/api/java/lang/Reflective­OperationException.html
  66. Scala Programming Language
    http://www.scala-lang.org/
  67. Run Scala in Apache Tomcat in 10 minutes
    http://www.softwaresecret­weapons.com/jspwiki/run-scala-in-apache-tomcat-in-10-minutes
  68. Fast Web Development With Scala
    http://chasethedevil.blog­spot.cz/2007/09/fast-web-development-with-scala.html
  69. Top five scripting languages on the JVM
    http://www.infoworld.com/d/developer-world/top-five-scripting-languages-the-jvm-855
  70. Proposal: Indexing access syntax for Lists and Maps
    http://mail.openjdk.java.net/pi­permail/coin-dev/2009-March/001108.html
  71. Proposal: Elvis and Other Null-Safe Operators
    http://mail.openjdk.java.net/pi­permail/coin-dev/2009-March/000047.html
  72. Java 7 : Oracle pushes a first version of closures
    http://www.baptiste-wicht.com/2010/05/oracle-pushes-a-first-version-of-closures/
  73. Groovy: An agile dynamic language for the Java Platform
    http://groovy.codehaus.org/Operators
  74. Better Strategies for Null Handling in Java
    http://www.slideshare.net/Step­han.Schmidt/better-strategies-for-null-handling-in-java
  75. Control Flow in the Java Virtual Machine
    http://www.artima.com/under­thehood/flowP.html
  76. Java Virtual Machine
    http://en.wikipedia.org/wi­ki/Java_virtual_machine
  77. ==, .equals(), compareTo(), and compare()
    http://leepoint.net/notes-java/data/expressions/22com­pareobjects.html
  78. New JDK7 features
    http://openjdk.java.net/pro­jects/jdk7/features/
  79. Project Coin: Bringing it to a Close(able)
    http://blogs.sun.com/darcy/en­try/project_coin_bring_clo­se
  80. CloseableFinder source code
    http://blogs.sun.com/darcy/re­source/ProjectCoin/Closea­bleFinder.java
  81. Joe Darcy blog about JDK
    http://blogs.sun.com/darcy
  82. Java 7 – more dynamics
    http://www.baptiste-wicht.com/2010/04/java-7-more-dynamics/
  83. New JDK 7 Feature: Support for Dynamically Typed Languages in the Java Virtual Machine
    http://java.sun.com/develo­per/technicalArticles/Dyn­TypeLang/index.html
Našli jste v článku chybu?
120na80.cz: Ochablé svaly mohou značit vážnou nemoc

Ochablé svaly mohou značit vážnou nemoc

120na80.cz: Poslední možnost změnit zdravotní pojišťovnu

Poslední možnost změnit zdravotní pojišťovnu

Lupa.cz: Proč jsou firemní počítače pomalé?

Proč jsou firemní počítače pomalé?

Podnikatel.cz: EET a účetní programy. Vše hotovo?

EET a účetní programy. Vše hotovo?

DigiZone.cz: Banaxi: videa kdekoli na světě

Banaxi: videa kdekoli na světě

Vitalia.cz: Jak Ondra o astma přišel

Jak Ondra o astma přišel

Vitalia.cz: Tesco nabízí desítky tun jídla zdarma

Tesco nabízí desítky tun jídla zdarma

DigiZone.cz: Nova opět stahuje „milionáře“

Nova opět stahuje „milionáře“

Vitalia.cz: Muž, který miluje příliš. Ženám neimponuje

Muž, který miluje příliš. Ženám neimponuje

Vitalia.cz: Antibakteriální mýdla nepomáhají, spíš škodí

Antibakteriální mýdla nepomáhají, spíš škodí

Podnikatel.cz: Instalatér, malíř a elektrikář. "Vymřou"?

Instalatér, malíř a elektrikář. "Vymřou"?

DigiZone.cz: Světový pohár v přímém přenosu na ČT

Světový pohár v přímém přenosu na ČT

DigiZone.cz: Digi Slovakia zařazuje stanice SPI

Digi Slovakia zařazuje stanice SPI

Lupa.cz: Patička e-mailu závazná jako vlastnoruční podpis?

Patička e-mailu závazná jako vlastnoruční podpis?

Vitalia.cz: Tohle jsou nejlepší česká piva podle odborníků

Tohle jsou nejlepší česká piva podle odborníků

DigiZone.cz: Wimbledon na Nova Sport až do 2019

Wimbledon na Nova Sport až do 2019

DigiZone.cz: Rapl: seriál, který vás smíří s ČT

Rapl: seriál, který vás smíří s ČT

Lupa.cz: Blíží se konec Wi-Fi sítí bez hesla?

Blíží se konec Wi-Fi sítí bez hesla?

Vitalia.cz: dTest odhalil ten nejlepší kečup

dTest odhalil ten nejlepší kečup

Vitalia.cz: Jsou vegani a vyrábějí nemléko

Jsou vegani a vyrábějí nemléko