Dyon: spojení předností Rustu a dynamicky typovaných programovacích jazyků (2.část)

24. 8. 2017
Doba čtení: 24 minut

Sdílet

 Autor: Rust project
I v dnešním článku budeme pokračovat v popisu neobvyklého jazyka Dyon s dynamickým typovým systémem. Zabývat se budeme zejména smyčkami ∃ (any) a ∀ (all), datovými typy Result a Option, zpracováním chyb a kontrolou životnosti objektů.

Obsah

1. Krátké zopakování z první části článku – speciální typy programových smyček

2. Smyčky konstruované pomocí ∃ a ∀

3. Získání přesnějších informací o výsledcích smyček: klauzule where, why a why not

4. Použití klauzule where u smyček minmax

5. Použití klauzulí why a why not u smyček ∃ a ∀

6. Datový typ Option

7. Datový typ Result

8. Operátor ?

9. „Probublávání“ hodnot none() a err(x) při použití operátoru ?

10. Kontrola modifikátoru mut u parametrů a argumentů funkcí

11. Uživatelsky definované objekty

12. Uživatelsky definované ad-hoc typy

13. Životnost objektů

14. Použití funkce clone

15. Repositář s demonstračními příklady

16. Odkazy na Internetu

1. Krátké zopakování z první části článku – speciální typy programových smyček

Již minule jsme se seznámili s tím, že kromě dvou univerzálních smyček nazvaných loop (nekonečná smyčka) a for (několik forem počítané smyčky i smyčky typu for-each) existují v jazyku Dyon i další varianty programových smyček, které se typicky používají pro zpracování polí (ostatně práce s poli tvoří základ pro většinu skriptů, které jsou v Dyonu psány). Připomeňme si, že můžeme použít tyto smyčky:

Konstrukce Alternativní zápis Význam
sift   vytvoření pole z předávaných hodnot
     
sum suma prvků
prod výsledek vynásobení všech prvků
     
min   zjištění minima
max   zjištění maxima
     
any test, zda je výraz pravdivý alespoň pro jeden prvek
all test, zda je výraz pravdivý pro všechny prvky

Příklad použití:

a := [3,2,1,10,1]
 
minimum := min i { a[i] }
println(minimum)
 
maximum := max i { a[i] }
println(maximum)
 
suma := sum i len(a) { a[i] }
println(suma)
 
product := prod i len(a) { a[i] }
println(product)

S výsledky:

1
10
17
60

2. Smyčky konstruované pomocí ∃ a ∀

Ve skutečnosti je možné většinu těchto smyček chápat jako specializovanou formu reduce s počáteční hodnotou akumulátoru a funkcí aplikovanou postupně na prvky, kterými se iteruje. Viditelné je to zejména u těchto šesti smyček:

Smyčka Prováděná operace Počáteční hodnota
sum + 0
prod * 1
     
min < acc none()
max > acc none()
     
any logický součet false
all logický součin true

Podívejme se nyní na způsob použití programových smyček all a any pro zjištění, zda nějaké jednorozměrné pole obsahuje alespoň jednu zápornou hodnotu či zda jsou všechny hodnoty kladné. Můžeme použít obou typů smyček. Povšimněte si způsobu zápisu podmínky do složených závorek:

fn special_loops_all_any() {
    println("Special loops: all, any")
 
    a := [3,2,1,10,1]
    println(a)
 
    has_negative_values := any i { a[i] < 0 }
    println(has_negative_values)
 
    all_values_positive := all i { a[i] > 0 }
    println(all_values_positive)
 
    a := [3,2,-1,10,1]
    println(a)
 
    has_negative_values := any i { a[i] < 0 }
    println(has_negative_values)
 
    all_values_positive := all i { a[i] > 0 }
    println(all_values_positive)
 
    println("")
}

Výsledek běhu této funkce:

Special loops: all, any
[3, 2, 1, 10, 1]
false
true
[3, 2, -1, 10, 1]
true
false

3. Získání přesnějších informací o výsledcích smyček: klauzule where, why a why not

Programovací jazyk Dyon dokáže k hodnotám typu bool a f64 (což jsou dva základní a vlastně i jediné primitivní datové typy) navázat nepovinné pole obsahující další metainformace o dané hodnotě. Toto nepovinné pole se jmenuje secrets a lze ho použít k zápisu uživatelských dat (pokud to má význam). U některých programových smyček se secrets používá pro uložení informace do výsledné hodnoty produkované programovou smyčkou:

Smyčka Secrets Získání secrets
min index minimálního prvku where()
max index maximálního prvku where()
     
any index prvku, který první splnil podmínku why()
all index prvku, který první nesplnil podmínku why()

Z předchozí tabulky je patrné, že u smyček min a max použijeme klauzuli where(). Tato klauzule se sice zapisuje jako funkce, ale jedná se o prvek jazyka. U smyčky any se pomocí why() získá index prvku, který první splnil podmínku – to ovšem platí jen u návratové hodnoty true. U smyčky all se naopak pomocí why not/(why(!…)) získá index prvního prvku, který podmínku nesplnil. Platné je to ovšem jen v případě, že smyčka all vrátila hodnotu false. To mj. znamená, že u těchto dvou smyček budeme zápis why(…) či why(!…) prakticky vždy používat v podmínce.

4. Použití klauzule where u smyček minmax

Klauzuli where použijeme především u programových smyček min a max, protože tak můžeme velmi snadno získat index prvku s minimální či naopak maximální hodnotou. Použití je velmi jednoduché, jak je to ostatně patrné z následující funkce, kde je where zvýrazněno:

fn special_loops_min_max_secrets() {
    println("Special loops: min max, secrets")
 
    a := [3,2,1,10,1]
    println(a)
 
    minimum := min i { a[i] }
    print("Min: ")
    print(minimum)
    print(" at index: ")
    println(where(minimum))
 
    maximum := max i { a[i] }
    print("Max: ")
    print(maximum)
    print(" at index: ")
    println(where(maximum))
 
    println("")
}

Výsledek běhu této funkce:

Special loops: min max, secrets
[3, 2, 1, 10, 1]
Min: 1 at index: [2]
Max: 10 at index: [3]

Poznámka: povšimněte si, že pokud vstupní pole obsahuje alespoň jeden prvek, je zajištěno, že where vrátí index prvku, na rozdíl od dále popsané klauzule why. To znamená, že v kódu nemusíme používat žádné podmínky a přímo přistupovat k výsledkům smyčky a metainformacím navázaným na tyto výsledky.

5. Použití klauzulí why a why not u smyček ∃ a ∀

Zatímco u klauze where jsme měli jistotu, že vrátí index prvku s minimální či maximální hodnotou, je tomu u klauzulí why a why not poněkud jinak, protože tyto klauzule jsou použity v kombinaci s programovými smyčkami ∃ a ∀. U smyčky any lze why() použít jen u návratové hodnoty true. U smyčky all se naopak používá why not (zapisované (why(!…)), ovšem jen v případě, že smyčka all vrátila hodnotu false. Opět se podívejme na příklady:

fn special_loops_any_secrets() {
    println("Special loops: any, secrets")
 
    a := [3,2,1,10,1]
    println(a)
 
    has_negative_values := any i { a[i] < 0 }
    print("Has negative values: ")
    if has_negative_values {
        print("Yes, at index: ")
        println(why(has_negative_values))
    } else {
        println("No")
    }
 
    a := [3,2,-1,10,-1]
    println(a)
 
    has_negative_values := any i { a[i] < 0 }
    print("Has negative values: ")
    if has_negative_values {
        print("Yes, at index: ")
        println(why(has_negative_values))
    } else {
        println("No")
    }
 
    println("")
}

Výsledek běhu této funkce:

Special loops: any, secrets
[3, 2, 1, 10, 1]
Has negative values: No
[3, 2, -1, 10, -1]
Has negative values: Yes, at index: [2]
fn special_loops_all_secrets() {
    println("Special loops: all, secrets")
 
    a := [3,2,1,10,1]
    println(a)
 
    all_values_positive := all i { a[i] > 0 }
    print("All values are positive: ")
    if all_values_positive {
        println("Yes")
    } else {
        print("No, 1st non-positive value found at index: ")
        println(why(!all_values_positive))
    }
 
    a := [3,2,-1,10,-1]
    println(a)
 
    all_values_positive := all i { a[i] > 0 }
    print("All values are positive: ")
    if all_values_positive {
        println("Yes")
    } else {
        print("No, 1st non-positive value found at index: ")
        println(why(!all_values_positive))
    }
 
    println("")
}

Výsledek běhu této funkce:

Special loops: all, secrets
[3, 2, 1, 10, 1]
All values are positive: Yes
[3, 2, -1, 10, -1]
All values are positive: No, 1st non-positive value found at index: [2]

6. Datový typ Option

S datovým typem Option jsme se již setkali při popisu vlastností programovacího jazyka Rust. Připomeňme si tedy, že díky existenci tohoto typu je možné elegantně obejít většinu nectností speciálních hodnot (někde ukazatelů, jinde zase pro změnu referencí) typu None, null či nil. Při použití typu Option je totiž explicitně specifikováno, že je nějaká hodnota nepovinná popř. volitelná (podle kontextu). Navíc jsme jako programátoři přinuceni se explicitně zpracováním nepovinné/volitelné hodnoty zabývat. Datový typ Option tvoří obálku nad samotnou reprezentovanou hodnotou popř. reprezentuje prázdnou obálku. S tímto typem jsou spojeny především tři funkce:

Funkce Význam
some(any) vytvoří obálku s hodnotou libovolného typu
none() vytvoří prázdnou obálku (jedná se o jedináčka)
unwrap(option) (rozbalení) vrátí hodnotu uloženou v obálce

Podívejme se na použití těchto tří funkcí. Je to velmi snadné:

o := some(42)
println(o)
 
o = none()
println(o)
 
o = some(2)
println(unwrap(o))
 
o = none()
//println(unwrap(o))
 
if o != none() {
    println(unwrap(o))
}

Povšimněte si zejména testu, zda je obálka prázdná (zde se kód odlišuje od Rustu).

Výsledek běhu příkladu:

some(42)
none()
2
false

unwrap() nelze volat pro hodnotu none():

 --- ERROR ---
main (src/main.dyon)
test_option_type (src/main.dyon)
unwrap
 
Expected `some(_)`
12,20:     println(unwrap(o))
12,20:                    ^

Poznámka: prozatím nelze použít pattern matching, který by se zde hodil.

7. Datový typ Result

I další užitečný datový typ nazvaný Result jsme si již v tomto seriálu popsali, ovšem v kontextu Rustu a nikoli Dyonu. Připomeňme si tedy, že v mnoha případech nemusí být použití datového typu Option tím nejlepším řešením. Pro příklad nemusíme chodit daleko – předpokládejme, že budeme chtít, aby například funkce pro dělení celých čísel vracela v případě pokusu o dělení nulou chybové hlášení a nikoli nicneříkající hodnotu none(). K tomuto účelu se v programovacím jazyku Rust a nyní i Dyon používá datová struktura nazvaná příhodně Result. Tato datová struktura se podobá Option, ovšem s tím rozdílem, že obaluje buď výsledek (třeba návratovou hodnotu volané funkce) nebo informaci o chybě. K dispozici jsou následující pomocné funkce:

Funkce Význam
ok(any) vytvoří obálku s hodnotou libovolného typu
err(any) vytvoří obálku s hodnotou reprezentující chybu (například chybové hlášení)
is_ok(result) dotaz (predikát), zda pracujeme s bezchybnou hodnotou
is_err(result) dotaz (predikát), zda pracujeme s informací o chybě
unwrap(result) (rozbalení) vrátí hodnotu uloženou v obálce
unwrap_err(result) (rozbalení) vrátí hodnotu reprezentující chybu

Opět se podívejme na jednoduchý příklad:

r := ok(42)
println(r)
println(is_ok(r))
println(is_err(r))
 
r = err("Very serious")
println(r)
println(is_ok(r))
println(is_err(r))
 
r = ok(2)
println(unwrap(r))
//println(unwrap_err(r))
 
r = err("Very serious")
//println(unwrap(r))
println(unwrap_err(r))
 
r = ok(42)
if is_ok(r) {
    println(unwrap(r))
} else {
    println(unwrap_err(r))
}

S výsledky:

ok(42)
true
false
err("Very serious")
false
true
2
Very serious
42

Poznámka: opět platí, že prozatím nelze použít pattern matching, který by se zde hodil.

8. Operátor ?

Pokud vytvoříme funkci div počítající podíl dvou čísel, která bude vracet typ Result, můžeme jednoduše zabezpečit, že nikdy nedojde k dělení nulou:

fn div(x,y) -> {
    if y == 0 {
        return err("Div by 0")
    } else {
        return ok(x/y)
    }
}

Popř. můžeme použít idiomatičtější zápis:

fn div(x,y) -> {
    return if y == 0 { err("Div by 0") }
           else { ok(x/y) }
}

Tuto funkci si můžeme snadno otestovat:

fn test_div() {
    d := div(10, 5)
    println(d)
    e := div(1, 0)
    println(e)
}

S výsledky:

ok(2)
err("Div by 0")

Co se ovšem stane v případě, že budeme mít několik vzájemně se volajících funkcí, které si budou výsledek div() předávat a používat ho? Nebylo by asi praktické stále volat is_ok(…) a is_err(…), navíc by se kvůli množství podmínek do zápisu algoritmu zbytečně vneslo mnoho kontrol speciálních (chybových) stavů. Řešení samozřejmě existuje a spočívá v použití operátoru ?. Tento operátor se zapisuje za jméno volané funkce a umožňuje provést kontrolu, zda je výsledek volání (typu Result) roven ok(hodnota). Pokud tomu tak není, je funkce ihned ukončena a návratovou hodnotou je err(zpráva). Operátor ? tedy slouží k tomu, aby se v kódu nemuselo explicitně zapisovat:

r := nějaká_funkce()
if is_err(r) {
    return r
}
...
...
...

9. „Probublávání“ hodnot none() a err(x) při použití operátoru ?

Podívejme se nyní na to, jak je možné elegantně vyřešit volání funkce div() uvnitř jiné funkce, která používá výsledek dělení a tudíž i potenciální chybový stav. Funkce div() je stále stejná:

fn div(x,y) -> {
    if y == 0 {
        return err("Div by 0")
    } else {
        return ok(x/y)
    }
}

Další funkce je určena k přičtení nějakého offsetu k výsledku dělení. Ovšem ve chvíli, kdy by se mělo dělit nulou, budeme chtít výpočet ihned ukončit a vrátit původní chybu. Toho docílíme snadno právě díky použití operátoru ? (ten je zapsán za uzavírací kulatou závorku):

fn div_add(x, y, z) -> {
    r := div(x, y)?
    println(r)
    return ok(r + z)
}

Poslední dva příkazy println+return se provedou jen ve chvíli, kdy se nedělilo nulou. Ostatně se o tom můžeme velmi snadno přesvědčit:

fn test_div_question_op() {
    r1 := div_add(10, 5, 100)
    println(r1)
 
    r2 := div_add(10, 0, 100)
    println(r2)
}

S výsledky:

2
ok(102)
err("Div by 0")

První dvojka vznikla byla vypsána ve funkci div_add.

Poznámka: operátor ? tedy nemá nic společného s ternárním céčkovým operátorem, který není nutné do jazyka Dyon implementovat, protože si if-else používá ve výrazech.

10. Kontrola modifikátoru mut u parametrů a argumentů funkcí

Již minule jsme se zmínili o tom, že pokud má funkce modifikovat hodnoty svých argumentů, musí se u těchto argumentů zapsat modifikátor mut. Stejný modifikátor je nutné použít i při volání funkce, čímž dává programátor najevo, že je srozuměn s tím, že se daný parametr může měnit. Kontrola přítomnosti tohoto modifikátoru ale ve skutečnosti probíhá v celém řetězci volání. Ostatně podívejme se na jednoduchý příklad, v němž se funkce inc volá z jiné funkce call_inc volané ze třetí funkce functions:

fn inc(mut x) {
    x += 1
}
 
fn call_inc(mut x) {
    inc(mut x)
}
 
fn functions() {
    x := 1
    println(x)
    call_inc(mut x)
    println(x)
}

Modifikátor mut je skutečně nutné použít na všech čtyřech zvýrazněných místech, nemůžeme se ho tedy „zbavit“ například uvnitř call_inc:

fn inc(mut x) {
    x += 1
}
 
fn call_inc(mut x) {
    inc(x)
}
 
fn functions() {
    x := 1
    println(x)
    call_inc(mut x)
    println(x)
}
 --- ERROR ---
In `src/main.dyon`:
 
Could not find function `inc`
 
Did you mean:
- inc(mut)
 
6,5:     inc(x)
6,5:     ^

A už vůbec ne při volání call_inc:

fn inc(mut x) {
    x += 1
}
 
fn call_inc(mut x) {
    inc(mut x)
}
 
fn functions() {
    x := 1
    println(x)
    call_inc( x)
    println(x)
}
 --- ERROR ---
In `src/main.dyon`:
 
Could not find function `call_inc`
 
Did you mean:
- call_inc(mut)
 
12,5:     call_inc(x)
12,5:     ^

11. Uživatelsky definované objekty

Uživatelsky definované objekty jsou postavené na klasických asociativních polích (slovnících, hash mapách), takže se jedná o přístup, který můžeme znát z programovacího jazyka Lua. Pro přístup k atributům objektů se používá buď tečková notace či alternativně přístup přes klíč, jehož jméno je v uvozovkách (jde o řetězec). Opět se zde nabízí srovnání s programovacím jazykem Lua:

fn test_objects() {
    c := {real:10, imag:20}
    println(c)
 
    c.real = 1000
    println(c)
 
    c["real"] = 0
    println(c)
}

S výsledky:

{imag: 20, real: 10}
{imag: 20, real: 1000}
{imag: 20, real: 0}

Podobně jako v případě běžných proměnných, i při modifikaci atributů se provádí kontrola, zda nedochází ke změně typu ukládané hodnoty:

fn test_objects() {
    c := {real:10, imag:20}
    println(c)
 
    c.real = 1000
    println(c)
 
    c["real"] = "x"
    println(c)
}
 --- ERROR ---
main (src/main.dyon)
test_objects (src/main.dyon)
 
Expected assigning to text
23,5:     c["real"] = "x"
23,5:     ^

Atributy lze k objektu přidávat za běhu, a to tečkovou notací a současně operátorem := (nikoli pouze =, což by nebylo konzistentní):

fn test_objects() {
    c := {real:10, imag:20}
    println(c)
 
    c.real = 1000
    println(c)
 
    c["real"] = 0
    println(c)
 
    c.name := "komplexni cislo"
    println(c)
}

S výsledky:

{real: 10, imag: 20}
{real: 1000, imag: 20}
{real: 0, imag: 20}
{real: 0, name: "komplexni cislo", imag: 20}

12. Uživatelsky definované ad-hoc typy

Programovací jazyk Dyon podporuje deklaraci takzvaných ad-hoc typů, díky nimž lze vytvářet struktury podobné třídám. Podívejme se na jednoduchý příklad, v němž nejdříve vytvoříme „konstruktor“ pro třídu Complex (musíme si však uvědomit, že termín „konstruktor“ a „třída“ je zde uveden pouze pro sémantickou podobnost s podobnými konstrukcemi známými z některých jiných jazyků):

fn new_complex(real, imag) -> Complex {
    return {real: clone(real),
            imag: clone(imag)}
}

V tomto konstruktoru jsme pouze pojmenovali slovník, který je výsledkem volání funkce.

Ve skutečnosti můžeme nové pojmenování Complex použít ve chvíli, kdy je nutné určit typ parametrů funkce (někdy to nutné není a můžeme se spolehnout na dynamický typový systém):

fn print_complex(c: Complex) {
    print(c.real)
    print("+j")
    print(c.imag)
}

Chování konstruktoru new_complex i funkce print_complex si můžeme snadno odzkoušet:

fn main() {
    cplx := new_complex(10, 20)
    print_complex(cplx)
}

S výsledkem:

10+j20

Poznámka: žádnou další podporu pro práci s objekty v sémantice programovacího jazyka Dyon (prozatím) nenajdeme, dokonce ani nejsou přímo podporovány traity.

13. Životnost objektů

Jednou z velmi důležitých vlastností programovacího jazyka Dyon je kontrola životnosti (častěji se možná používá termín viditelnosti) objektů. Díky této kontrole je možné se obejít bez klasického garbage collectoru, protože objekt je možné z paměti odstranit ve chvíli, kdy je již zřejmé, že není viditelný (živý). Na druhou stranu to však klade poněkud větší nároky na programátora, který na některých místech programu musí explicitně určit, jaká je životnost proměnné či parametru funkce.

V následujícím programu je vše v pořádku, protože životnost parametrů funkcí je omezena jen na těla funkcí. Je tomu tak z toho důvodu, že vynásobením vzniká nová hodnota:

fn foo(a) -> {
    return a*2
}
 
fn bar(a) -> {
    return 3*foo(a)
}
 
fn test_lifetimes() {
    x := bar(10)
    println(x)
}

Co když však budeme chtít přímo vrátit parametr předaný do funkce? V tomto případě nevzniká nová hodnota a současně je životnost parametru delší než je oblast platnosti funkce:

fn foo(a) -> {
    return a
}
 
fn bar(a) -> {
    return 3*foo(a)
}
 
fn test_lifetimes() {
    x := bar(10)
    println(x)
}

Program se tedy nepřeloží, ovšem z chybového hlášení je zřejmé, jak provést nápravu:

 --- ERROR ---
In `src/main.dyon`:
 
Requires `a: 'return`
47,12:     return a
47,12:            ^

Úpravou a: 'return specifikujeme, že životnost parametru a má být větší – má se rozšířit i na volající funkci:

fn foo(a: 'return) -> {
    return a
}
 
fn bar(a) -> {
    return 3*foo(a)
}
 
fn test_lifetimes() {
    x := bar(10)
    println(x)
}

Podobně můžeme zvětšovat životnost i přes funkci bar do funkce test_lifetimes:

fn foo(a: 'return) -> {
    return a
}
 
fn bar(a: 'return) -> {
    return foo(a)
}
 
fn test_lifetimes() {
    b := 10
    x := bar(b)
    println(x)
}

Ve skutečnosti se při deklaraci může použít zápis x: 'y, který znamená, že proměnná x má mít minimálně takovou životnost, jako proměnná y. Zápis s 'return je speciálním případem (ostatně žádná proměnná se return jmenovat nemůže :-)

14. Použití funkce clone

Většinou je explicitní deklarace životnosti objektů pro programátory zbytečně pracné a namísto rozšiřování životnosti použijí funkci clone(), která danou hodnotu naklonuje. Po naklonování nás již nemusí zajímat, jaká byla životnost původní hodnoty. Příklad jsme si vlastně již ukázali u konstruktoru komplexních čísel, kde jsme explicitně naklonovali parametry funkce a klony jsme použili v atributech nového objektu (slovníku):

fn new_complex(real, imag) -> Complex {
    return {real: clone(real),
            imag: clone(imag)}
}

Pokud volání clone() vynecháme:

fn new_complex(real, imag) -> Complex {
    return {real: real,
            imag: imag}
}

Dojde při překladu zdrojového kódu k chybě:

bitcoin_skoleni

 --- ERROR ---
In `src/main.dyon`:
 
Requires `real: 'return`
31,12:     return {real: real,
31,12:            ^
32,1:             imag: imag}

A právě v této kontrole podle mého názoru spočívá největší přednost celé technologie kontroly životnosti – programátor je překladačem umozorněn na potenciální problémy a může program adekvátně změnit, většinou defenzivní kopií. Pěkně to shrnuje tento komentář.

15. Repositář s demonstračními příklady

Většina ukázek z předchozích kapitol byla přidána do několika demonstračních příkladů, které byly uloženy do Git repositáře dostupného na adrese https://github.com/tisnik/pre­sentations. Demonstrační příklady si můžete v případě potřeby stáhnout i jednotlivě bez nutnosti klonovat celý repositář (ovšem u projektů je lepší mít celý repositář, abyste nemuseli pracně stahovat všechny potřebné soubory):

16. Odkazy na Internetu

  1. Secrets design – optional information in bool and f64
    https://github.com/Piston­Developers/dyon/issues/266
  2. Option value design
    https://github.com/Piston­Developers/dyon/issues/172
  3. Result value design ( err(x)/ok(x))
    https://github.com/Piston­Developers/dyon/issues/82
  4. ∑/sum, ∏/prod, min, max, sift, ∃/any, ∀/all loops
    https://github.com/Piston­Developers/dyon/issues/119
  5. Dyon: tutoriál
    http://www.piston.rs/dyon-tutorial/
  6. Repositář s programovacím jazykem Dyon
    https://github.com/Piston­Developers/dyon
  7. Dyon: A rusty dynamically typed scripting language
    https://rust.libhunt.com/project/dyon
  8. Dyon snippets
    https://github.com/Piston­Developers/dyon_snippets
  9. Scripting without garbage collector
    http://blog.piston.rs/2016/02/21/scrip­ting-without-garbage-collector/
  10. Podpora pro „matematické“ smyčky
    https://github.com/Piston­Developers/dyon/issues/119
  11. Rust-clippy Wiki
    https://github.com/rust-lang-nursery/rust-clippy/wiki
  12. Rust-clippy
    https://rust.libhunt.com/project/rust-clippy
  13. ndarray – dokumentace k modulu
    https://bluss.github.io/rust-ndarray/master/ndarray/index.html
  14. ndarray – Crate
    https://crates.io/crates/ndarray
  15. rustup
    https://www.rustup.rs/
  16. rustup: the Rust toolchain installer (Git repositář + dokumentace)
    https://github.com/rust-lang-nursery/rustup.rs
  17. The Rust FFI Omnibus
    http://jakegoulding.com/rust-ffi-omnibus/
  18. Build Script Support
    http://doc.crates.io/build-script.html
  19. Calling Rust From Python
    https://bheisler.github.i­o/post/calling-rust-in-python/
  20. Calling Rust in Python (komentáře k předchozímu článku)
    https://www.reddit.com/r/rus­t/comments/63iy5a/calling_rus­t_in_python/
  21. CFFI Documentation
    https://cffi.readthedocs.i­o/en/latest/
  22. Build Script Support
    http://doc.crates.io/build-script.html
  23. Creating a shared and static library with the gnu compiler [gcc]
    http://www.adp-gmbh.ch/cpp/gcc/create_lib.html
  24. ctypes — A foreign function library for Python
    https://docs.python.org/2/li­brary/ctypes.html
  25. FFI: Foreign Function Interface
    https://doc.rust-lang.org/book/ffi.html
  26. Primitive Type pointer
    https://doc.rust-lang.org/std/primitive.pointer.html
  27. Cargo: správce projektů a balíčků pro programovací jazyk Rust
    https://mojefedora.cz/cargo-spravce-projektu-a-balicku-pro-programovaci-jazyk-rust/
  28. Network Communication and Serialization in Rust
    https://www.safaribookson­line.com/blog/2014/01/28/net­work-communication-serialization-rust/
  29. Crate bincode
    http://tyoverby.com/binco­de/bincode/index.html
  30. Struct std::fs::File
    https://doc.rust-lang.org/std/fs/struct.File.html
  31. Trait std::io::Seek
    https://doc.rust-lang.org/std/io/trait.Seek.html
  32. Trait std::io::Read
    https://doc.rust-lang.org/std/io/trait.Read.html
  33. Trait std::io::Write
    https://doc.rust-lang.org/std/io/trait.Write.html
  34. Trait std::io::BufRead
    https://doc.rust-lang.org/std/io/trait.BufRead.html
  35. Module std::io::prelude
    https://doc.rust-lang.org/std/io/prelude/index.html
  36. std::net::IpAddr
    https://doc.rust-lang.org/std/net/enum.IpAddr.html
  37. std::net::Ipv4Addr
    https://doc.rust-lang.org/std/net/struct.Ipv4Addr.html
  38. std::net::Ipv6Addr
    https://doc.rust-lang.org/std/net/struct.Ipv6Addr.html
  39. TcpListener
    https://doc.rust-lang.org/std/net/struct.TcpLis­tener.html
  40. TcpStream
    https://doc.rust-lang.org/std/net/struct.TcpStream.html
  41. Binary heap (Wikipedia)
    https://en.wikipedia.org/wi­ki/Binary_heap
  42. Binární halda (Wikipedia)
    https://cs.wikipedia.org/wi­ki/Bin%C3%A1rn%C3%AD_halda
  43. Halda (datová struktura)
    https://cs.wikipedia.org/wi­ki/Halda_%28datov%C3%A1_struk­tura%29
  44. Struct std::collections::HashSet
    https://doc.rust-lang.org/std/collections/struc­t.HashSet.html
  45. Struct std::collections::BTreeSet
    https://doc.rust-lang.org/std/collections/struc­t.BTreeSet.html
  46. Struct std::collections::BinaryHeap
    https://doc.rust-lang.org/std/collections/struc­t.BinaryHeap.html
  47. Set (abstract data type)
    https://en.wikipedia.org/wi­ki/Set_%28abstract_data_ty­pe%29#Language_support
  48. Associative array
    https://en.wikipedia.org/wi­ki/Associative_array
  49. Hash Table
    https://en.wikipedia.org/wi­ki/Hash_table
  50. B-tree
    https://en.wikipedia.org/wiki/B-tree
  51. Pedro Celis: Robin Hood Hashing (naskenované PDF!)
    https://cs.uwaterloo.ca/re­search/tr/1986/CS-86–14.pdf
  52. Robin Hood hashing
    http://codecapsule.com/2013/11/11/ro­bin-hood-hashing/
  53. Robin Hood hashing: backward shift deletion
    http://codecapsule.com/2013/11/17/ro­bin-hood-hashing-backward-shift-deletion/
  54. Module std::collections
    https://doc.rust-lang.org/std/collections/
  55. Module std::vec
    https://doc.rust-lang.org/nightly/std/vec/index.html
  56. Struct std::collections::VecDeque
    https://doc.rust-lang.org/std/collections/struc­t.VecDeque.html
  57. Struct std::collections::LinkedList
    https://doc.rust-lang.org/std/collections/struc­t.LinkedList.html
  58. Module std::fmt
    https://doc.rust-lang.org/std/fmt/
  59. Macro std::println
    https://doc.rust-lang.org/std/macro.println.html
  60. Enum std::result::Result
    https://doc.rust-lang.org/std/result/enum.Result.html
  61. Module std::result
    https://doc.rust-lang.org/std/result/
  62. Result
    http://rustbyexample.com/std/re­sult.html
  63. Rust stdlib: Option
    https://doc.rust-lang.org/std/option/enum.Option.html
  64. Module std::option
    https://doc.rust-lang.org/std/option/index.html
  65. Rust by example: option
    http://rustbyexample.com/std/op­tion.html
  66. Rust by example: if-let
    http://rustbyexample.com/flow_con­trol/if_let.html
  67. Rust by example: while let
    http://rustbyexample.com/flow_con­trol/while_let.html
  68. Rust by example: Option<i32>
    http://rustbyexample.com/std/op­tion.html
  69. An Overview of Macros in Rust
    http://words.steveklabnik.com/an-overview-of-macros-in-rust
  70. A Practical Intro to Macros in Rust 1.0
    https://danielkeep.github.io/practical-intro-to-macros.html
  71. The Rust Programming Language: macros
    https://doc.rust-lang.org/beta/book/macros.html
  72. Rust by example: 15 macro_rules!
    http://rustbyexample.com/macros.html
  73. Primitive Type isize
    https://doc.rust-lang.org/nightly/std/primi­tive.isize.html
  74. Primitive Type usize
    https://doc.rust-lang.org/nightly/std/primi­tive.usize.html
  75. Primitive Type array
    https://doc.rust-lang.org/nightly/std/primi­tive.array.html
  76. Module std::slice
    https://doc.rust-lang.org/nightly/std/slice/
  77. Rust by Example: 2.3 Arrays and Slices
    http://rustbyexample.com/pri­mitives/array.html
  78. What is the difference between Slice and Array (stackoverflow)
    http://stackoverflow.com/qu­estions/30794235/what-is-the-difference-between-slice-and-array
  79. Learning Rust With Entirely Too Many Linked Lists
    http://cglab.ca/~abeinges/blah/too-many-lists/book/
  80. Testcase: linked list
    http://rustbyexample.com/cus­tom_types/enum/testcase_lin­ked_list.html
  81. Operators and Overloading
    https://doc.rust-lang.org/book/operators-and-overloading.html
  82. Module std::ops
    https://doc.rust-lang.org/std/ops/index.html
  83. Module std::cmp
    https://doc.rust-lang.org/std/cmp/index.html
  84. Trait std::ops::Add
    https://doc.rust-lang.org/stable/std/ops/trait.Add.html
  85. Trait std::ops::AddAssign
    https://doc.rust-lang.org/std/ops/trait.AddAssign.html
  86. Trait std::ops::Drop
    https://doc.rust-lang.org/std/ops/trait.Drop.html
  87. Trait std::cmp::Eq
    https://doc.rust-lang.org/std/cmp/trait.Eq.html
  88. Struct std::boxed::Box
    https://doc.rust-lang.org/std/boxed/struct.Box.html
  89. Explore the ownership system in Rust
    https://nercury.github.io/rus­t/guide/2015/01/19/ownership­.html
  90. Rust's ownership and move semantic
    http://www.slideshare.net/sa­neyuki/rusts-ownership-and-move-semantics
  91. Trait std::marker::Copy
    https://doc.rust-lang.org/stable/std/marker/tra­it.Copy.html
  92. Trait std::clone::Clone
    https://doc.rust-lang.org/stable/std/clone/tra­it.Clone.html
  93. The Stack and the Heap
    https://doc.rust-lang.org/book/the-stack-and-the-heap.html
  94. Rust Compare: Pointers & References
    http://www.rust-compare.com/site/pointers.html
  95. Rust Compare: Parameters
    http://www.rust-compare.com/site/params.html
  96. Why does this compile? Automatic dereferencing?
    https://users.rust-lang.org/t/why-does-this-compile-automatic-dereferencing/2183
  97. Understanding Pointers, Ownership, and Lifetimes in Rust
    http://koerbitz.me/posts/Understanding-Pointers-Ownership-and-Lifetimes-in-Rust.html
  98. Rust lang series episode #25 — pointers (#rust-series)
    https://steemit.com/rust-series/@jimmco/rust-lang-series-episode-25-pointers-rust-series
  99. Rust – home page
    https://www.rust-lang.org/en-US/
  100. Rust – Frequently Asked Questions
    https://www.rust-lang.org/en-US/faq.html
  101. Destructuring and Pattern Matching
    https://pzol.github.io/get­ting_rusty/posts/20140417_des­tructuring_in_rust/
  102. The Rust Programming Language
    https://doc.rust-lang.org/book/
  103. Rust (programming language)
    https://en.wikipedia.org/wi­ki/Rust_%28programming_lan­guage%29
  104. Go – home page
    https://golang.org/
  105. Stack Overflow – Most Loved, Dreaded, and Wanted language
    https://stackoverflow.com/re­search/developer-survey-2016#technology-most-loved-dreaded-and-wanted
  106. Rust vs Go (dva roky staré hodnocení, od té doby došlo k posunům v obou jazycích)
    http://jaredforsyth.com/2014/03/22/rust-vs-go/
  107. Rust vs Go: My experience
    https://www.reddit.com/r/go­lang/comments/21m6jq/rust_vs_go_my_ex­perience/
  108. Friends of Rust (Organizations running Rust in production)
    https://www.rust-lang.org/en-US/friends.html
  109. Rust programs versus C++ g++
    https://benchmarksgame.ali­oth.debian.org/u64q/compa­re.php?lang=rust&lang2=gpp
  110. Další benchmarky (nejedná se o reálné příklady „ze života“)
    https://github.com/kostya/benchmarks
  111. Go na Redditu
    https://www.reddit.com/r/golang/
  112. Rust vs. Go
    http://vschart.com/compare/rust/vs/go-language
  113. Abstraction without overhead: traits in Rust
    https://blog.rust-lang.org/2015/05/11/traits.html
  114. Method Syntax
    https://doc.rust-lang.org/book/method-syntax.html
  115. Traits in Rust
    https://doc.rust-lang.org/book/traits.html
  116. Functional Programming in Rust – Part 1 : Function Abstraction
    http://blog.madhukaraphatak­.com/functional-programming-in-rust-part-1/
  117. Of the emerging systems languages Rust, D, Go and Nim, which is the strongest language and why?
    https://www.quora.com/Of-the-emerging-systems-languages-Rust-D-Go-and-Nim-which-is-the-strongest-language-and-why
  118. Chytré ukazatele (moderní verze jazyka C++) [MSDN]
    https://msdn.microsoft.com/cs-cz/library/hh279674.aspx
  119. UTF-8 Everywhere
    http://utf8everywhere.org/
  120. Rust by Example
    http://rustbyexample.com/
  121. Rust oficiálně ve Fedoře
    https://mojefedora.cz/rust-oficialne-ve-fedore/
  122. Resource acquisition is initialization
    https://en.wikipedia.org/wi­ki/Resource_acquisition_is_i­nitialization
  123. TIOBE index (October 2016)
    http://www.tiobe.com/tiobe-index/
  124. Porovnání Go, D a Rustu na OpenHubu:
    https://www.openhub.net/lan­guages/compare?language_na­me[]=-1&language_name[]=-1&language_name[]=dmd&lan­guage_name[]=golang&langu­age_name[]=rust&language_na­me[]=-1&measure=commits
  125. String Types in Rust
    http://www.suspectsemantic­s.com/blog/2016/03/27/str­ing-types-in-rust/
  126. Trait (computer programming)
    https://en.wikipedia.org/wi­ki/Trait_%28computer_program­ming%29
  127. Type inference
    https://en.wikipedia.org/wi­ki/Type_inference

Autor článku

Vystudoval VUT FIT a v současné době pracuje na projektech vytvářených v jazycích Python a Go.