Obsah
1. Novinky představené v jazyku Julia verze 1.0
3. Otestování základní funkcionality nové verze
4. Reprezentace chybějící hodnoty
6. Makro @enum a zápis hodnot v bloku
7. Změna oblasti viditelnosti proměnných ve smyčce for
10. Destructuring n-tic použitých pro předání parametrů do funkcí
11. Pojmenované prvky v n-ticích
13. Operátor ^ a celá záporná čísla reprezentující exponent
14. Odlišná pravidla při interpolaci řetězců
15. Implicitní spojení proměnné s řetězcovým literálem
16. Hodnoty s plovoucí řádovou čárkou a „tečkové“ operátory
17. Přepis základních funkcí novým globálním symbolem se stejným jménem
18. Pravděpodobně nezamýšlené změny v REPLu
19. Proměnné, jejichž jména jsou tvořena podtržítky
1. Novinky představené v jazyku Julia verze 1.0
V dnešním článku se zaměříme na popis změn v jazyku Julia, které nalezneme především ve verzi 1.0, s tím dovětkem, že některé novinky byly představeny i ve verzi 0.7. Verze 0.7 je totiž taktéž nově vydaná, snaží se být kompatibilní se staršími verzemi, ovšem některé příkazy zobrazují varování „deprecated“, tj. informaci o tom, že již nebudou dále podporovány. Ve verzi 1.0 už tyto vlastnosti nejsou podporovány vůbec. V praxi to znamená, že je nejdříve vhodné přejít na verzi 0.7, v ní si odladit vlastní skripty a aplikace (aby se nevypisovala varování) a teprve poté přejít na verzi 1.0 (popř. mít lokálně nainstalovány obě verze).
Vydání verze 1.0 má spíše netechnické důvody: další změny v jazyku zaváděné v budoucích verzích 1.1, 1.2 atd. totiž budou navrhovány takovým způsobem, aby byly zpětně kompatibilní právě s verzí 1.0 (případné nekompatibilní změny může přinést až verze 2.0, ta se však ještě neplánuje). Doba relativně rychlého a možná i poněkud chaotického vývoje jazyka Julia je tedy za námi, což je důležitá informace pro další využívání tohoto jazyka v praxi.
2. Instalace verze 1.0
V mnoha Linuxových distribucích se ještě verze 1.0 programovacího jazyka Julia nedostala do oficiálních repositářů. To si ostatně můžeme velmi snadno ověřit, například na stále podporované Fedoře 28 s využitím nástroje dnf. Povšimněte si, že v této distribuci je k dispozici pouze verze 0.6.3, která ani zdaleka neobsahuje všechny novinky uvedené ve verzi 0.7, natož ve verzi 1.0:
dnf info julia Last metadata expiration check: 1:29:20 ago on Thu 13 Sep 2018 06:44:42 AM EDT. Available Packages Name : julia Version : 0.6.3 Release : 1.fc28 Arch : x86_64 Size : 13 M Source : julia-0.6.3-1.fc28.src.rpm Repo : updates Summary : High-level, high-performance dynamic language for technical : computing URL : http://julialang.org/ License : MIT and LGPLv2+ and GPLv2+
To, že oficiální repositář distribuce ještě neobsahuje poslední verzi jazyka Julia, nám však nemusí vadit v případě, že používáme jednu z oficiálně podporovaných architektur, pro níž jsou již připraveny binární balíčky i se všemi potřebnými knihovnami (se všemi klady a zápory, které lokální instalace všech takových knihoven přináší!). Instalace balíčku na architekturu x86–64 je jednoduchá. Nejdříve si stáhneme příslušný tarball (archiv):
$ wget https://julialang-s3.julialang.org/bin/linux/x64/1.0/julia-1.0.0-linux-x86_64.tar.gz --2018-09-13 08:17:09-- https://julialang-s3.julialang.org/bin/linux/x64/1.0/julia-1.0.0-linux-x86_64.tar.gz Connecting to julialang-s3.julialang.org (julialang-s3.julialang.org)|151.101.54.49|:443... connected. HTTP request sent, awaiting response... 200 OK Length: 88896624 (85M) [application/octet-stream] Saving to: ‘julia-1.0.0-linux-x86_64.tar.gz’ julia-1.0.0-linux-x 100%[===================>] 84.78M 22.9MB/s in 4.9s 2018-09-13 08:17:14 (17.2 MB/s) - ‘julia-1.0.0-linux-x86_64.tar.gz’ saved [88896624/88896624]
A dále provedeme rozbalení archivu nástrojem tar:
tar xvfz julia-1.0.0-linux-x86_64.tar.gz
Vznikne adresářová struktura uložená v podadresáři „~/julia-1.0.0“ a tudíž dostupná pouze pro aktuálně přihlášeného uživatele (strom je zobrazen pouze do druhé úrovně):
julia-1.0.0 ├── bin │ └── julia ├── etc │ └── julia ├── include │ └── julia ├── lib │ ├── julia │ ├── libjulia.so -> libjulia.so.1.0 │ ├── libjulia.so.1 -> libjulia.so.1.0 │ └── libjulia.so.1.0 ├── LICENSE.md └── share ├── appdata ├── applications ├── doc ├── icons ├── julia └── man
Další možnost představuje použití připraveného obrazu pro nástroj Docker. Další informace o oficiálně připravených obrazech jsou dostupné na stránce https://hub.docker.com/_/julia/
3. Otestování základní funkcionality nové verze
Po rozbalení tarballu s jazykem Julia verze 1.0 způsobem ukázaným výše si pro jistotu otestujeme jeho základní funkcionalitu. Spustíme si proto interaktivní prostředí tohoto jazyka (neboli REPL), a to následujícím příkazem (připomeňme si, že jsme nijak neupravovali proměnnou PATH, tudíž musíme použít plnou cestu):
$ julia-1.0.0/bin/julia
Uvítat by nás měla následující zpráva. Pro jistotu si zkontrolujte, zda skutečně používáte správnou verzi (viz tučně zvýrazněná část zprávy):
_ _ _ _(_)_ | Documentation: https://docs.julialang.org (_) | (_) (_) | _ _ _| |_ __ _ | Type "?" for help, "]?" for Pkg help. | | | | | | |/ _` | | | | |_| | | | (_| | | Version 1.0.0 (2018-08-08) _/ |\__'_|_|_|\__'_| | Official https://julialang.org/ release |__/ | julia>
Podrobnější informace o verzi, podporované architektuře, použitých knihovnách atd. získáme zavoláním funkce versioninfo():
julia> versioninfo() Julia Version 1.0.0 Commit 5d4eaca0c9 (2018-08-08 20:58 UTC) Platform Info: OS: Linux (x86_64-pc-linux-gnu) CPU: Intel(R) Xeon(R) CPU E5440 @ 2.83GHz WORD_SIZE: 64 LIBM: libopenlibm LLVM: libLLVM-6.0.0 (ORCJIT, penryn)
Výzva julia> značí, že REPL jazyka Julia očekává zadání příkazů či definici funkce. Stiskem klávesy „?“ se přepneme do režimu nápovědy:
help?> search: ... Welcome to Julia 1.0.0. The full manual is available at https://docs.julialang.org/ as well as many great tutorials and learning resources: https://julialang.org/learning/ For help on a specific function or macro, type ? followed by its name, e.g. ?cos, or ?@time, and press enter. Type ; to enter shell mode, ] to enter package mode.
Ještě pro jistotu otestujeme některé další vlastnosti interpretru.
Deklarace proměnné a použití proměnné ve výrazu (operátor násobení je implicitní, stejně jako v matematice):
julia> x=10 10 julia> 2x+3x^2 320
Deklarace nové funkce s implicitním příkazem return:
julia> inc(x)=x+1 inc (generic function with 1 method)
Vytvoření objektu typu range a aplikace naší funkce inc na hodnoty z tohoto objektu:
julia> range(1, length=10) 1:10 julia> map(inc, range(1, length=10)) 10-element Array{Int64,1}: 2 3 4 5 6 7 8 9 10 11
4. Reprezentace chybějící hodnoty
Nově je v jazyku Julia definována speciální hodnota reprezentující (jakoukoli) chybějící hodnotu. Díky tomu není nutné si vymýšlet vlastní speciální hodnoty typu –1, prázdný řetězec atd. Tato speciální hodnota je dostupná pod jménem missing (opět si povšimněte, že uživatelé nejsou zbytečně zmateni z názvu typu null, který má pro matematiky jiný význam):
julia> missing missing
Tato hodnota má samozřejmě svůj datový typ, a to Missing:
julia> typeof(missing) Missing
Prakticky všechny operace s hodnotou missing jsou povoleny, a to s tím, že výsledkem bude taktéž missing:
julia> missing + 10 missing
julia> 10 + missing missing
Zajímavé je ovšem porovnání – missing evidentně doplňuje dvouhodnotovou Booleovu algebru:
julia> missing == missing missing
julia> missing != missing missing
julia> missing > missing missing
julia> missing < missing missing
Porovnání na identitu:
julia> missing === missing true
julia> missing !== missing false
Existuje i funkce ismissing(), která nahrazuje výše zmíněné porovnání a doporučuje se ji používat:
julia> ismissing(10) false
julia> ismissing(missing) true
Tato hodnota je využitelná všude, typicky může reprezentovat neznámou hodnotu v poli (řídké matici…):
julia> x=(1,2,3,missing,4,5) (1, 2, 3, missing, 4, 5)
julia> x=[1,2,3,missing,4,5] 6-element Array{Any,1}: 1 2 3 missing 4 5
Jen pro úplnost si doplňme, jak vypadá porovnání a další operace s další speciální hodnotou NaN. Ta má jiný význam a odlišné chování:
julia> NaN == NaN false
julia> NaN != NaN true
julia> NaN > NaN false
julia> NaN < NaN false
julia> NaN === NaN true
5. Deklarace nových operátorů
Na začátek si připomeňme, že v jazyce Julia je možné vytvářet a používat funkce (i proměnné), v jejichž jménu jsou znaky z Unicode. Příkladem může být standardní funkce pro výpočet druhé odmocniny:
help?> √ "√" can be typed by \sqrt<tab>
Příklad zavolání této funkce:
julia> √2 1.4142135623730951
Podobně třetí odmocnina:
julia> ∛1000 10.0
Podobné funkce si samozřejmě můžeme snadno vytvořit. Totéž platí i pro operátory, takže je možné vytvořit nový operátor pro Kroneckerův součin:
julia> const ⊗ = kron kron (generic function with 16 methods)
Příklady použití:
julia> 1 ⊗ 5 5
julia> A = [1 2; 3 4] 2×2 Array{Int64,2}: 1 2 3 4 julia> B = [im 1; 1 -im] 2×2 Array{Complex{Int64},2}: 0+1im 1+0im 1+0im 0-1im julia> A ⊗ B 4×4 Array{Complex{Int64},2}: 0+1im 1+0im 0+2im 2+0im 1+0im 0-1im 2+0im 0-2im 0+3im 3+0im 0+4im 4+0im 3+0im 0-3im 4+0im 0-4im
Nyní lze podobným způsobem vytvářet i nové operátory, které se skládají ze symbolu nějakého existujícího operátoru (kvůli prioritě) a Unicode znaku s horním či dolním indexem. Příklad vytvoření nového operátoru, který bude počítat délku přepony:
julia> +₂(a,b) = sqrt(a^2 + b^2) +₂ (generic function with 1 method) julia> 1 +₂ 2 2.23606797749979
Operátor pro součet v modulární aritmetice (modulo 8).
julia> +⁸(a,b) = (a+b)%8
Použití nového operátoru:
julia> 1 +⁸ 2 3
julia> 1 +⁸ 7 0
julia> 2 +⁸ 7 1
Podobně lze vytvořit operátor pro násobení:
julia> *⁸(a,b) = (a*b)%8 *⁸ (generic function with 1 method) julia> 2 *⁸ 7 6
Ve starší verzi jazyka nebyly takto pojmenované operátory povoleny:
julia> +⁸(a,b) = (a+b)%8 ERROR: syntax: invalid character "⁸" Stacktrace: [1] macro expansion at ./REPL.jl:97 [inlined] [2] (::Base.REPL.##1#2{Base.REPL.REPLBackend})() at ./event.jl:73
6. Makro @enum a zápis hodnot v bloku
Další jazyková úprava může být velmi užitečná ve chvíli, kdy se vytváří výčtový typ s mnoha hodnotami. Připomeňme si, že pro tento účel slouží makro @enum:
help?> @enum @enum EnumName[::BaseType] value1[=x] value2[=y] Create an Enum{BaseType} subtype with name EnumName and enum member values of value1 and value2 with optional assigned values of x and y, respectively. EnumName can be used just like other types and enum member values as regular values, such as ...
Ve starších verzích a samozřejmě i ve verzi 1.0 se výčtový typ deklaruje následujícím způsobem:
julia> @enum Languages c=1 python=2 julia=3 rust=4
Příklad použití:
julia> c::Languages c::Languages = 1 julia> julia::Languages julia::Languages = 3
Nově je možné ve verzi 1.0 použít i deklaraci výčtového typu rozepsanou na více řádků, což je čitelnější. Používají se zde pomocná klíčová slova begin a end:
@enum Languages begin c=1 python=2 julia=3 rust=4 end
Příklad použití:
julia> julia::Languages julia::Languages = 3
Pokus o použití předchozí deklarace ve verzi 0.6.3 ovšem skončí s chybou:
@enum Languages begin c=1 python=2 julia=3 rust=4 end ERROR: ArgumentError: invalid argument for Enum Languages: begin # REPL[15], line 2: c = 1 # REPL[15], line 3: python = 2 # REPL[15], line 4: julia = 3 # REPL[15], line 5: rust = 4 end Stacktrace: [1] macro expansion at ./REPL.jl:97 [inlined] [2] (::Base.REPL.##1#2{Base.REPL.REPLBackend})() at ./event.jl:73
7. Změna oblasti viditelnosti proměnných ve smyčce for
Programovací jazyk Julia je určen i lidem, kteří nemají vystudován žádný IT obor, což znamená, že některé vlastnosti jazyka jsou navrženy takovým způsobem, aby pro uživatele nepředstavovaly zbytečné pasti. Týká se to i změny konceptu viditelnosti řídicích proměnných v programové smyčce for, který se odlišuje od některých dalších (řekněme mainstreamových) jazyků, ovšem je přirozenější. Nejdříve se podívejme, jak se řídicí proměnné chovají ve starší verzi Julie.
Spustíme interpret Julie 0.6.3:
$ julia _ _ _ _(_)_ | A fresh approach to technical computing (_) | (_) (_) | Documentation: https://docs.julialang.org _ _ _| |_ __ _ | Type "?help" for help. | | | | | | |/ _` | | | | |_| | | | (_| | | Version 0.6.3 (2018-05-28 20:20 UTC) _/ |\__'_|_|_|\__'_| | |__/ | x86_64-redhat-linux
Vytvoříme proměnnou i a nastavíme jí nějakou hodnotu:
julia> i=-1000 -1000
Použijeme proměnnou téhož jména pro počítanou smyčku for:
julia> for i=1:10 println(i) end 1 2 3 4 5 6 7 8 9 10
Podíváme se na hodnotu proměnné i po ukončení smyčky:
julia> i 10
Můžeme vidět, že se hodnota proměnné změnila, konkrétně na poslední hodnotu, kterou měla proměnná v programové smyčce. Takové chování najdeme i v mnoha dalších programovacích jazycích, ovšem pro uživatele (matematiky, fyziky) může být toto chování poněkud matoucí. V Julii 1.0.0 je z tohoto důvodu situace odlišná, o čemž se opět můžeme přesvědčit:
julia> i=-1000 -1000 julia> for i=1:10 println(i) end 1 2 3 4 5 6 7 8 9 10
Po proběhnutí smyčky se podíváme na aktuální hodnotu proměnné i:
julia> i -1000
Vidíme, že se hodnota proměnné nezměnila – evidentně se ve smyčce použila jiná (lokální) proměnná
x=-1000 for x = 1,10 do print(x) end 1 2 3 4 5 6 7 8 9 10 print(x) -1000
Mění se i chování vnořených programových smyček ve chvíli, kdy ve vnitřní smyčce modifikujeme hodnotu počitadla smyčky vnější. Ve starší verzi měla tato změna lokální vliv, ve verzi 1.0.0 je počitadlo vždy na začátku iterace přepsáno svojí správnou hodnotou:
Chování starší verze:
for i in [1,2,3], j in [1,2,3] println(i*j) end 1 2 3 2 4 6 3 6 9 for i in [1,2,3], j in [1,2,3] println(i*j) i = -1 end 1 -2 -3 2 -2 -3 3 -2 -3
Chování verze 1.0, v níž je na začátku každé iterace vnitřní smyčky obnovena hodnota počitadla smyčky vnější:
for i in [1,2,3], j in [1,2,3] println(i*j) end 1 2 3 2 4 6 3 6 9 for i in [1,2,3], j in [1,2,3] println(i*j) i = -1 end 1 2 3 2 4 6 3 6 9
Proměnná i je ovšem měnitelná, pouze se na začátku každé iterace obnoví:
for i in [1,2,3], j in [1,2,3] i = -1 println(i*j) end -1 -2 -3 -1 -2 -3 -1 -2 -3
8. Použití klauzule outer
S předchozí změnou chování programových smyček souvisí i zavedení klauzule outer, kterou je možné specifikovat, že programová smyčka má namísto lokálního počitadla použít již dříve definovanou proměnnou. Tato proměnná samozřejmě musí být v daném kontextu viditelná. Podívejme se na způsob použití této klauzule uvnitř funkce:
julia> function f() i = 0 for outer i = 1:10 end return i end f (generic function with 2 methods)
Při zavolání této funkce se vrátí hodnota 10, tj. koncová hodnota počitadla smyčky:
julia> f() 10
Pokud naopak klauzuli outer nepoužijeme, bude se aplikovat pravidlo o lokální proměnné popsané v předchozí kapitole:
julia> function f() i = 0 for i = 1:10 end return i end f (generic function with 2 methods)
Nyní funkce po svém zavolání vrátí původní hodnotu přiřazenou do proměnné i:
julia> f() 0
9. Nová makra pro logování
Ve starších verzích programovacího jazyka Julia bylo možné pro logování použít funkce info() a warn(). Jejich použití je snadné a přímočaré:
julia> info("341") INFO: 341
julia> warn("42") WARNING: 42
Ve verzi 1.0 již tyto funkce neexistují a namísto nich byla vytvořena makra @info, @warn a taktéž @error:
O tom, že funkce info() již skutečně neexistuje, se přesvědčíme snadno:
julia> info("341") ERROR: UndefVarError: info not defined Stacktrace: [1] top-level scope at none:0
Použití nových maker @info, @warn a @error je snadné:
julia> @info("341") [ Info: 341
julia> @warn("asi prepisu cely disk") ┌ Warning: asi prepisu cely disk └ @ Main REPL[7]:1
julia> @error("Chyba pri zapisu") ┌ Error: Chyba pri zapisu └ @ Main REPL[4]:1
Hlavní důvody, proč se namísto původních logovacích funkcí mají používat makra, jsou pěkně shrnuty v tomto komentáři:
- Makro umožňuje „líné“ vygenerování zprávy jen ve chvíli, kdy je to skutečně zapotřebí (parametry makra totiž není nutné vyhodnocovat před jeho voláním).
- Makra umožňují vytvářet unikátní identifikátory řádku, na němž se nachází, takže je například umožněno preciznější filtrování dlouhých logů, například nějakým externím nástrojem.
- Makra umožňují shromažďovat různé (meta)informace již v čase překladu.
Navíc bych přidal další vlastnost – při zákazu logování se makra mohou expandovat na prázdný příkaz, kdežto funkce se budou stále volat, i když nebudou provádět žádnou činnost.
julia> error("Chyba pri zapisu") ERROR: Chyba pri zapisu Stacktrace: [1] error(::String) at ./error.jl:33 [2] top-level scope at none:0
10. Destructuring n-tic použitých pro předání parametrů do funkcí
Další novou a užitečnou vlastností je takzvaný destructuring n-tic, který se použije ve chvíli, kdy jsou n-tice použity při předávání parametrů do funkcí. Již v hlavičce funkce je možné specifikovat nejenom fakt, že se bude předávat n-tice, ale i kolik prvků bude tato n-tice mít a jak se budou (po rozložení) jmenovat. Ukažme si jednoduchý příklad s funkcí, které se předá n-tice se dvěma prvky a výsledkem volání funkce bude součet těchto dvou prvků. Povšimněte si především zápisu: vnější závorky označují argumenty funkce, kdežto závorky vnitřní fakt, že se bude předávat n-tice (x,y):
julia> f((x,y),) = x+y f (generic function with 1 method)
Vytvoříme si novou n-tici, konkrétně tedy dvojici s prvky 1 a 2 (opět je nutné použít závorky):
julia> dvojice=(1,2) (1, 2)
A zavoláme funkci f, které předáme naši n-tici:
julia> f(dvojice) 3
U předchozí verze 0.6 jazyka Julia nelze n-tice použít:
julia> f((x,y),) = x+y ERROR: syntax: "(x,y)" is not a valid function argument name Stacktrace: [1] macro expansion at ./REPL.jl:97 [inlined] [2] (::Base.REPL.##1#2{Base.REPL.REPLBackend})() at ./event.jl:73
11. Pojmenované prvky v n-ticích
I další vlastnost souvisí s n-ticemi. Syntaxe jazyka Julia byla rozšířena o možnost používat pojmenované prvky v n-ticích. To je velmi užitečná vlastnost, protože nám například umožňuje vytvořit si dvojici představující bod v 2D prostoru a přímo pojmenovat prvky (ty tedy nebudou určeny pouze svým indexem):
julia> point=(x=10, y=20) (x = 10, y = 20)
Způsob zobrazení hodnoty n-tice:
julia> point (x = 10, y = 20)
Pro přístup k jednotlivým prvkům n-tice se používá tečková notace:
julia> point.x 10
julia> point.y 20
Opět platí, že ve starší verzi jazyka není tato nová syntaxe podporována:
julia> point=(x=10, y=20) ERROR: syntax: assignment not allowed inside tuple Stacktrace: [1] macro expansion at ./REPL.jl:97 [inlined] [2] (::Base.REPL.##1#2{Base.REPL.REPLBackend})() at ./event.jl:73
12. Makro @isdefined
Tato kapitola bude velmi stručná, protože se v ní pouze seznámíme s existencí makra pojmenovaného @isdefined. Toto makro lze kdykoli použít pro zjištění, zda je nějaká proměnná definována či nikoli. Díky tomu, že se jedná o makro nemusí docházet k vyhodnocování hodnoty.
Proměnná point byla definována v předchozí kapitole:
julia> @isdefined point true
Zato proměnnou vector jsme prozatím vůbec nepoužili:
julia> @isdefined vector false
Makro @isdefined lze použít kdykoli a kdekoli:
julia> for i in 1:10 println(i) println(@isdefined i) end
13. Operátor ^ a celá záporná čísla reprezentující exponent
I tato kapitola bude velmi krátká a zmíníme se v ní o chování operátoru ^ v případě, že exponentem je záporné celé číslo. Starší verze jazyka Julia neumožňovaly přímý zápis x−1:
julia> x=2 2 julia> x^-1 ERROR: DomainError: Stacktrace: [1] literal_pow(::Base.#^, ::Int64, ::Type{Val{-1}}) at ./intfuncs.jl:208 [2] macro expansion at ./REPL.jl:97 [inlined] [3] (::Base.REPL.##1#2{Base.REPL.REPLBackend})() at ./event.jl:73
Nová verze jazyka již tento zápis bez problémů umožňuje:
julia> x=2 2 julia> x^-1 0.5 julia> x^-10 0.0009765625
14. Odlišná pravidla při interpolaci řetězců
Další změna se týká odlišných pravidel při interpolaci řetězců, tj. při náhradě jména proměnné v řetězci její hodnotou (to dokáže i BASH, TCL atd.). Ve starších verzích jazyka Julia lze interpolaci provést prakticky jakkoli, pouze je důležité zajistit, aby název proměnné byl jednoznačný (nesmí za ním ihned následovat alfanumerický znak):
julia> x="hello"
Všechny následující interpolace budou funkční:
julia> "$x world!" "hello world!"
julia> "$x`world!" "hello`world!"
julia> "$x෴ world!" "hello෴ world!"
Nová verze jazyka je nepatrně odlišná a kontroluje, jestli není za názvem řetězce nějaký nepovolený (unicode) znak:
julia> x="hello"
julia> "$x world!" "hello world!"
julia> "$x`world!" "hello`world!"
Povšimněte si, že se dokonce vypíše i nápověda, jak interpolaci provést korektně a naprosto jednoznačně:
julia> "$x෴ world!" ERROR: syntax: interpolated variable $x ends with invalid character "෴"; use "$(x)" instead.
15. Implicitní spojení proměnné s řetězcovým literálem
Ve starších verzích programovacího jazyka Julia bylo možné spojit hodnotu proměnné (převedenou na řetězec) s řetězcovým literálem, a to bez explicitního použití operátoru (podobně, jako u násobení).
julia> x="world" "world"
Spojení řetězcového literálu a proměnné:
julia> "hello "x "hello world"
Nové verze již toto chování zakazuje, protože výše uvedený zápis může velmi pravděpodobně vzniknout spíše chybou uživatele:
julia> x="world" "world"
Při pokusu o spojení řetězcového literálu s proměnnou nyní dojde k chybě:
julia> "hello "x ERROR: syntax: cannot juxtapose string literal
Pro spojení řetězců se nyní musí použít operátor *:
julia> "hello " * x "hello world"
16. Hodnoty s plovoucí řádovou čárkou a „tečkové“ operátory
Připomeňme si, že v programovacím jazyku Julia je možné použít různé „tečkové“ operátory, které slouží k tomu, aby se příslušná operace provedla mezi všemi prvky předaného vektoru nebo matice. Příkladem může být výpočet druhých mocnin každého prvku vstupního vektoru:
a=[1,2,3,4] print(a.^2) [1, 4, 9, 16]
Tečku lze použít prakticky před všemi operátory, ovšem problémy (nebo spíše zmatky) nastávají ve chvíli, kdy je před operátorem zapsána například hodnota „2.“, která samozřejmě odpovídá plnému zápisu „2.0“.
Chování starších verzí jazyka při použití mezery za číslem a bez použití mezery je následující:
julia> 2 .* [1,2,3] 3-element Array{Int64,1}: 2 4 6 julia> 2.*[1,2,3] 3-element Array{Int64,1}: 2 4 6
Výše uvedené výsledky jsou logické, ovšem už méně logické je chování v případě, že se „tečkovým“ operátorem násobí dvě skalární hodnoty:
julia> typeof(2.*3) Int64
V tomto případě se evidentně vynásobila dvě celá čísla a pro násobení byl použit tečkový operátor.
Naproti tomu když mezi tečku a hvězdičku přidáme mezeru, provede se vynásobení hodnoty 2.0 a 3, takže výsledkem bude číslo s plovoucí řádovou čárkou:
julia> typeof(2. *3) Float64
Ve verzi 1.0 nejsou některé kombinace povoleny. Při použití mezery je vše v pořádku:
julia> 2 .* [1,2,3] 3-element Array{Int64,1}: 2 4 6
Ovšem vynechání mezery již znamená chybu (nejasnost pro uživatele), takže tento zápis je v nové verzi zakázán:
julia> 2.*[1,2,3] ERROR: syntax: invalid syntax "2.*"; add space(s) to clarify
julia> typeof(2.*3) ERROR: syntax: invalid syntax "2.*"; add space(s) to clarify
Lepší je tedy buď oddělovat operátory mezerou nebo namísto zkráceného zápisu 2. použít raději 2.0:
julia> typeof(2. *3) Float64
julia> typeof(2.0*3) Float64
17. Přepis základních funkcí novým globálním symbolem se stejným jménem
Ve starších verzích programovacího jazyka Julia bylo možné, například pouhým omylem, přepsat některou ze základních funkcí. To sice na jednu stranu ukazuje na velkou flexibilitu jazyka, na stranu druhou však takový přepis může vést k chybám při volání dalších funkcí a při používání knihoven. Podívejme se nyní na chování Julie 0.6.3.
Deklarace nové globální proměnné, jejíž jméno s ničím nekoliduje, je samozřejmě bezproblémové:
julia> global x = 10 10
Volání standardní funkce sin, opět bez problémů:
julia> sin(pi/2) 1.0
Přepis funkce sin vytvořením globální proměnné stejného jména:
julia> global sin = 20 WARNING: imported binding for sin overwritten in module Main 20
Pouze se vypíše varování, ovšem přepis se zdařil.
Nyní již volání standardní funkce sin selže:
julia> sin(pi/2) ERROR: MethodError: objects of type Int64 are not callable Stacktrace: [1] macro expansion at ./REPL.jl:97 [inlined] [2] (::Base.REPL.##1#2{Base.REPL.REPLBackend})() at ./event.jl:73
Nová verze jazyka Julia je v tomto ohledu mnohem striktnější:
Deklarace nové globální proměnné, jejíž jméno s ničím nekoliduje, je opět bezproblémové:
julia> global x = 10 10
Volání standardní funkce sin:
julia> sin(pi/2) 1.0
Pokus o přepis funkce sin vytvořením globální proměnné stejného jména ovšem nyní selže:
julia> global sin = 20 ERROR: cannot assign variable Base.sin from module Main Stacktrace: [1] top-level scope at none:0
18. Pravděpodobně nezamýšlené změny v REPLu
Některé změny, které byly implementovány v rámci verzí 0.7 a 1.0 mohou být nezamýšlené (tj. možná budou prohlášeny za chyby). Týká se to například situace, v níž uvnitř programové smyčky měníme hodnotu vnější proměnné – to vše v rámci interaktivního REPLu. U verze 0.6.3 a i u všech starších verzí je chování předvídatelné a odpovídá tomu, že proměnná a je viditelná na stejné úrovni, jako samotná programová smyčka:
julia> a = 0 0 julia> for i = 1:10 a+=1 end julia> a 10
Ve verzi 1.0 se však setkáme s tím, že proměnná a vůbec není uvnitř programové smyčky viditelná. Toto chování pravděpodobně souvisí se změnami, které jsme si popsali v sedmé a osmé kapitole:
julia> a = 0 0 julia> for i = 1:10 a+=1 end ERROR: UndefVarError: a not defined Stacktrace: [1] top-level scope at ./REPL[86]:2 [inlined] [2] top-level scope at ./none:0
julia> function x() a=0 for i=1:10 a+=1 end print(a) end x (generic function with 1 method) julia> x() 10
19. Proměnné, jejichž jména jsou tvořena podtržítky
Na závěr se zmiňme o relativně malé a zdánlivě nevýznamné změně, která souvisí s proměnnými, jejichž jména jsou tvořena pouze jedním podtržítkem nebo větším množstvím podtržítek. Starší verze jazyka Julia rozpoznávala pouze proměnnou pojmenovanou „_“, do které bylo možné přiřadit hodnotu a dokonce i hodnotu přečíst (v tomto případě se jen hlásilo varování). Naproti tomu proměnné „__“, „___“ atd. byly považovány za běžné proměnné a žádné kontroly při jejich čtení nebyly prováděny. Následuje ukázka chování starších verzí Julie:
julia> _=42 42 julia> _ WARNING: deprecated syntax "_ as an rvalue". 42 julia> _+10 WARNING: deprecated syntax "_ as an rvalue". 52
__ je ovšem (ve starší verzi) naprosto běžná proměnná:
julia> __=-1 -1
julia> __ -1
Nová verze jazyka Julia považuje všechny proměnné „_“, „__“, „___“ atd. za speciální skupinu proměnných, do nichž je možné jen zapisovat, ale nikoli číst jejich hodnotu. Mají se tedy použít pouze v případě, kdy je přiřazení nutné provést jen ze syntaktického hlediska, ovšem všem čtenářům kódu se má připomenout, že se hodnota ihned zahodí:
julia> _=42 42
Čtení hodnoty této proměnné již není možné:
julia> _ ERROR: all-underscore identifier used as rvalue
Použití ve výrazu (na pravé straně od přiřazení) je taktéž čtení:
julia> _+10 ERROR: syntax: all-underscore identifier used as rvalue
Totéž platí i pro proměnnou „__“:
julia> __=-1 -1
julia> __ ERROR: all-underscore identifier used as rvalue
20. Odkazy na Internetu
- Dokumentace – Julia 1.0
https://docs.julialang.org/en/v1/ - Julia 1.0
https://julialang.org/blog/2018/08/one-point-zero - Julia 1.0 Released
https://juliacomputing.com/press/2018/08/10/Julia-1.0-Released.html - Julia v0.7.0 Release Notes
https://github.com/JuliaLang/julia/blob/master/HISTORY.md - JuliaCan 2018
http://juliacon.org/2018/ - Julia 1.0 release (Juliacon 2018 reception founders talk) – YouTube
https://www.youtube.com/watch?v=1jN5wKvN-Uk&index=2&t=0s&list=PLP8iPy9hna6Qsq5_-zrg0NTwqDSDYtfQB - Julia v1.0.0 Release Notes
https://github.com/JuliaLang/julia/blob/master/NEWS.md - Concurrency (computer science)
https://en.wikipedia.org/wiki/Category:Concurrency_%28computer_science%29 - Tasks (aka Coroutines) [Julia]
http://julia.readthedocs.io/en/latest/manual/control-flow/#man-tasks - Koprogram
https://cs.wikipedia.org/wiki/Koprogram - Coroutine
https://en.wikipedia.org/wiki/Coroutine - Coroutines in C
http://www.chiark.greenend.org.uk/~sgtatham/coroutines.html - S-expression (Wikipedia)
https://en.wikipedia.org/wiki/S-expression - S-Expressions (Rosetta Code)
http://rosettacode.org/wiki/S-Expressions - Metaprogramming (Julia)
http://julia.readthedocs.io/en/latest/manual/metaprogramming/ - Introducing Julia/Metaprogramming
https://en.wikibooks.org/wiki/Introducing_Julia/Metaprogramming - Tutorial for the Common Lisp Loop Macro
http://www.ai.sri.com/pkarp/loop.html - CS 2101 Parallel Computing with Julia
https://www.coursehero.com/file/11508091/CS-2101-Parallel-Computing-with-Julia/ - Julia By Example
https://samuelcolvin.github.io/JuliaByExample/ - Tasks and Parallel Computing
http://docs.julialang.org/en/release-0.4/stdlib/parallel/ - clock(3) – Linux man page
http://linux.die.net/man/3/clock - rand_r(3) – Linux man page
http://linux.die.net/man/3/rand_r - atan2(3) – Linux man page
http://linux.die.net/man/3/atan2 - Calling C and Fortran Code
http://docs.julialang.org/en/release-0.4/manual/calling-c-and-fortran-code/?highlight=symbol - Array Programming
https://en.wikipedia.org/wiki/Array_programming - Discovering Array Languages
http://archive.vector.org.uk/art10008110 - no stinking loops – Kalothi
http://www.nsl.com/ - Vector (obsahuje odkazy na články, knihy a blogy o programovacích jazycích APL, J a K)
http://www.vector.org.uk/ - APL Interpreters
http://www.vector.org.uk/?area=interpreters - APL_(programming_language
http://en.wikipedia.org/wiki/APL_(programming_language - APL FAQ
http://www.faqs.org/faqs/apl-faq/ - APL FAQ (nejnovější verze)
http://home.earthlink.net/~swsirlin/apl.faq.html - A+
http://www.aplusdev.org/ - APLX
http://www.microapl.co.uk/ - FreeAPL
http://www.pyr.fi/apl/index.htm - J: a modern, high-level, general-purpose, high-performance programming language
http://www.jsoftware.com/ - K, Kdb: an APL derivative for Solaris, Linux, Windows
http://www.kx.com - openAPL (GPL)
http://sourceforge.net/projects/openapl - Parrot APL (GPL)
http://www.parrotcode.org/ - Learning J (Roger Stokes)
http://www.jsoftware.com/help/learning/contents.htm - Rosetta Code
http://rosettacode.org/wiki/Main_Page - Why APL
http://www.acm.org/sigapl/whyapl.htm - Introducing Julia/Functions
https://en.wikibooks.org/wiki/Introducing_Julia/Functions - Functions (Julia documentation)
http://docs.julialang.org/en/release-0.4/manual/functions/ - Evaluate binomial coefficients
http://rosettacode.org/wiki/Evaluate_binomial_coefficients - Ackermann function
http://rosettacode.org/wiki/Ackermann_function - Julia (front page)
http://julialang.org/ - Julia – dokumentace
http://docs.julialang.org/en/release-0.4/ - Julia – repositář na GitHubu
https://github.com/JuliaLang/julia - Julia (programming language, Wikipedia)
https://en.wikipedia.org/wiki/Julia_%28programming_language%29 - IJulia
https://github.com/JuliaLang/IJulia.jl - Introducing Julia
https://en.wikibooks.org/wiki/Introducing_Julia - Julia: the REPL
https://en.wikibooks.org/wiki/Introducing_Julia/The_REPL - Month of Julia
https://github.com/DataWookie/MonthOfJulia - Learn X in Y minutes (where X=Julia)
https://learnxinyminutes.com/docs/julia/ - New Julia language seeks to be the C for scientists
http://www.infoworld.com/article/2616709/application-development/new-julia-language-seeks-to-be-the-c-for-scientists.html - Julia: A Fast Dynamic Language for Technical Computing
http://karpinski.org/publications/2012/julia-a-fast-dynamic-language - The LLVM Compiler Infrastructure
http://llvm.org/ - Julia: benchmarks
http://julialang.org/benchmarks/ - Type system
https://en.wikipedia.org/wiki/Type_system - Half-precision floating-point format
https://en.wikipedia.org/wiki/Half-precision_floating-point_format - These are a few of my Favourite Things (that are coming with Julia 1.0)
https://white.ucc.asn.au/2018/06/01/Julia-Favourite-New-Things.html - A Julia Language Blog Aggregator
https://www.juliabloggers.com/ - What is the difference between 1.0 and 1. ?
https://groups.google.com/forum/#!topic/julia-users/aycsd2iAktE - Julia in the classroom
https://julialang.org/teaching/ - High-Performance Scientific Computing for Astrophysics
http://www.personal.psu.edu/~ebf11/teach/astro585/ - Julia Scientific Programming (Coursera)
https://www.coursera.org/learn/julia-programming - Introducing Julia/Controlling the flow
https://en.wikibooks.org/wiki/Introducing_Julia/Controlling_the_flow - Julia Box: Run Julia in your Browser
https://juliabox.com/ - Intro to Julia for data science
https://www.youtube.com/watch?v=SLE0vz85Rqo - Intro to dynamical systems in Julia
https://www.youtube.com/watch?v=13hqE_1a158