Hlavní navigace

Novinky představené v jazyku Julia verze 1.0

Pavel Tišnovský

Před měsícem byla představena nová verze jazyka Julia. Autoři přiřadili této verzi číslo 1.0, čímž naznačili, že došlo ke stabilizaci tohoto jazyka a že všechny nové vlastnosti budou s verzí 1.0 kompatibilní. Dnes si některé novinky představíme.

Doba čtení: 26 minut

Sdílet

11. Pojmenované prvky v n-ticích

12. Makro @isdefined

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

20. Odkazy na Internetu

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.

Poznámka: na druhou stranu bylo užitečné, že si Julia prošla počátečním „chaotickým“ vývojem, protože za šest let vývoje bylo možné si vyzkoušet různé úpravy syntaxe a sémantiky, měnit chování makrosystému atd.

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+
Poznámka: konkrétně pro Fedoru lze balíček získat i alternativním způsobem z copru, pokud vám nevadí používání nightly buildů.

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
Poznámka: většina ukázek, s nimiž se seznámíme v navazujících kapitolách, bude používat jednu nebo obě výše uvedené verze jazyka Julia. Konkrétně se tedy bude jednat o starší verzi 0.6.3 nainstalovanou z oficiálních balíčků Fedory (28) a dále se bude jednat o verzi 1.0.0 nainstalovanou jen lokálně (rozbalením tarballu). Interaktivní smyčka REPL první verze se spouští běžně příkazem julia (prakticky odkudkoli), druhá verze pak příkazem ~/julia-1.0.0/bin/julia (právě z důvodu použití dvou různých variant jazyka asi není vhodné si přidávat ~/julia-1.0.0/bin/ na PATH).

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)
Poznámka: mimochodem si povšimněte verze libLLVM. Starší verze Julie bývají linkovány oproti starší verzi LLVM, což se může negativně odrazit na výkonu přeloženého kódu.

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
Poznámka: zde již můžeme vidět první odchylku od starších verzí jazyka Julia, v nichž stačilo napsat range(1, 10) a nikoli explicitně range(1, length=10). Explicitní uvedené druhého parametru je čitelnější, protože v range lze specifikovat i krok.

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á

Poznámka: podobné chování nalezneme i v jazyku Lua, s nímž má Julia poměrně hodně společných vlastností (indexování prvků v poli od jedničky, syntaxe s mnoha klíčovými slovy atd.):
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:

  1. 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).
  2. 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.
  3. 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.

Poznámka: je nutné si dát pozor na rozdíl mezi makrem @error a funkcí error. Funkce error totiž slouží k vyhození výjimky a její použití je tedy odlišné:
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
Poznámka: s destructuringem n-tic jsme se již setkali například v jazyku Rust.

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"
Poznámka: použití operátoru * a nikoli + opět vychází z toho, že je jazyk Julia určen (i) matematikům a fyzikům. Obecně je totiž operace + v naprosté většině případů komutativní, což ale spojení řetězců určitě nesplňuje: „hello“ + „world“ != „world“ + „hello“. Naproti tomu operace * komutativní být nemusí. Příkladem může být násobení matic nebo kvaternionů.

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
Poznámka: tato chyba je ovšem hlášena pouze tehdy, pokud již byla funkce sin volána a tudíž importována. Pokud se tedy nějaká standardní funkce nepoužívá, není důvod bránit se deklaracím proměnných s jejím jménem (ostatně kdo si vůbec pamatuje všechny standardní funkce?).

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
Poznámka: toto chování se skutečně projevuje v REPLu, nikoli v běžných modulech ani ve funkcích:
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é:

cif-tip-digitalizaceCR

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

  1. Dokumentace – Julia 1.0
    https://docs.julialang.org/en/v1/
  2. Julia 1.0
    https://julialang.org/blog/2018/08/one-point-zero
  3. Julia 1.0 Released
    https://juliacomputing.com/pres­s/2018/08/10/Julia-1.0-Released.html
  4. Julia v0.7.0 Release Notes
    https://github.com/JuliaLan­g/julia/blob/master/HISTO­RY.md
  5. JuliaCan 2018
    http://juliacon.org/2018/
  6. Julia 1.0 release (Juliacon 2018 reception founders talk) – YouTube
    https://www.youtube.com/wat­ch?v=1jN5wKvN-Uk&index=2&t=0s&list=PLP8iPy9hna6Qsq5_-zrg0NTwqDSDYtfQB
  7. Julia v1.0.0 Release Notes
    https://github.com/JuliaLan­g/julia/blob/master/NEWS.md
  8. Concurrency (computer science)
    https://en.wikipedia.org/wi­ki/Category:Concurrency_%28com­puter_science%29
  9. Tasks (aka Coroutines) [Julia]
    http://julia.readthedocs.i­o/en/latest/manual/control-flow/#man-tasks
  10. Koprogram
    https://cs.wikipedia.org/wi­ki/Koprogram
  11. Coroutine
    https://en.wikipedia.org/wi­ki/Coroutine
  12. Coroutines in C
    http://www.chiark.greenen­d.org.uk/~sgtatham/corouti­nes.html
  13. S-expression (Wikipedia)
    https://en.wikipedia.org/wiki/S-expression
  14. S-Expressions (Rosetta Code)
    http://rosettacode.org/wiki/S-Expressions
  15. Metaprogramming (Julia)
    http://julia.readthedocs.i­o/en/latest/manual/metapro­gramming/
  16. Introducing Julia/Metaprogramming
    https://en.wikibooks.org/wi­ki/Introducing_Julia/Meta­programming
  17. Tutorial for the Common Lisp Loop Macro
    http://www.ai.sri.com/pkarp/loop.html
  18. CS 2101 Parallel Computing with Julia
    https://www.coursehero.com/fi­le/11508091/CS-2101-Parallel-Computing-with-Julia/
  19. Julia By Example
    https://samuelcolvin.github­.io/JuliaByExample/
  20. Tasks and Parallel Computing
    http://docs.julialang.org/en/release-0.4/stdlib/parallel/
  21. clock(3) – Linux man page
    http://linux.die.net/man/3/clock
  22. rand_r(3) – Linux man page
    http://linux.die.net/man/3/rand_r
  23. atan2(3) – Linux man page
    http://linux.die.net/man/3/atan2
  24. Calling C and Fortran Code
    http://docs.julialang.org/en/release-0.4/manual/calling-c-and-fortran-code/?highlight=symbol
  25. Array Programming
    https://en.wikipedia.org/wi­ki/Array_programming
  26. Discovering Array Languages
    http://archive.vector.org­.uk/art10008110
  27. no stinking loops – Kalothi
    http://www.nsl.com/
  28. Vector (obsahuje odkazy na články, knihy a blogy o programovacích jazycích APL, J a K)
    http://www.vector.org.uk/
  29. APL Interpreters
    http://www.vector.org.uk/?a­rea=interpreters
  30. APL_(programming_language
    http://en.wikipedia.org/wi­ki/APL_(programming_langu­age
  31. APL FAQ
    http://www.faqs.org/faqs/apl-faq/
  32. APL FAQ (nejnovější verze)
    http://home.earthlink.net/~swsir­lin/apl.faq.html
  33. A+
    http://www.aplusdev.org/
  34. APLX
    http://www.microapl.co.uk/
  35. FreeAPL
    http://www.pyr.fi/apl/index.htm
  36. J: a modern, high-level, general-purpose, high-performance programming language
    http://www.jsoftware.com/
  37. K, Kdb: an APL derivative for Solaris, Linux, Windows
    http://www.kx.com
  38. openAPL (GPL)
    http://sourceforge.net/pro­jects/openapl
  39. Parrot APL (GPL)
    http://www.parrotcode.org/
  40. Learning J (Roger Stokes)
    http://www.jsoftware.com/hel­p/learning/contents.htm
  41. Rosetta Code
    http://rosettacode.org/wiki/Main_Page
  42. Why APL
    http://www.acm.org/sigapl/whyapl.htm
  43. Introducing Julia/Functions
    https://en.wikibooks.org/wi­ki/Introducing_Julia/Functi­ons
  44. Functions (Julia documentation)
    http://docs.julialang.org/en/release-0.4/manual/functions/
  45. Evaluate binomial coefficients
    http://rosettacode.org/wi­ki/Evaluate_binomial_coef­ficients
  46. Ackermann function
    http://rosettacode.org/wi­ki/Ackermann_function
  47. Julia (front page)
    http://julialang.org/
  48. Julia – dokumentace
    http://docs.julialang.org/en/release-0.4/
  49. Julia – repositář na GitHubu
    https://github.com/JuliaLang/julia
  50. Julia (programming language, Wikipedia)
    https://en.wikipedia.org/wi­ki/Julia_%28programming_lan­guage%29
  51. IJulia
    https://github.com/JuliaLan­g/IJulia.jl
  52. Introducing Julia
    https://en.wikibooks.org/wi­ki/Introducing_Julia
  53. Julia: the REPL
    https://en.wikibooks.org/wi­ki/Introducing_Julia/The_REPL
  54. Month of Julia
    https://github.com/DataWo­okie/MonthOfJulia
  55. Learn X in Y minutes (where X=Julia)
    https://learnxinyminutes.com/doc­s/julia/
  56. New Julia language seeks to be the C for scientists
    http://www.infoworld.com/ar­ticle/2616709/application-development/new-julia-language-seeks-to-be-the-c-for-scientists.html
  57. Julia: A Fast Dynamic Language for Technical Computing
    http://karpinski.org/publi­cations/2012/julia-a-fast-dynamic-language
  58. The LLVM Compiler Infrastructure
    http://llvm.org/
  59. Julia: benchmarks
    http://julialang.org/benchmarks/
  60. Type system
    https://en.wikipedia.org/wi­ki/Type_system
  61. Half-precision floating-point format
    https://en.wikipedia.org/wiki/Half-precision_floating-point_format
  62. These are a few of my Favourite Things (that are coming with Julia 1.0)
    https://white.ucc.asn.au/2018/06/01/Ju­lia-Favourite-New-Things.html
  63. A Julia Language Blog Aggregator
    https://www.juliabloggers.com/
  64. What is the difference between 1.0 and 1. ?
    https://groups.google.com/fo­rum/#!topic/julia-users/aycsd2iAktE
  65. Julia in the classroom
    https://julialang.org/teaching/
  66. High-Performance Scientific Computing for Astrophysics
    http://www.personal.psu.e­du/~ebf11/teach/astro585/
  67. Julia Scientific Programming (Coursera)
    https://www.coursera.org/learn/julia-programming
  68. Introducing Julia/Controlling the flow
    https://en.wikibooks.org/wi­ki/Introducing_Julia/Contro­lling_the_flow
  69. Julia Box: Run Julia in your Browser
    https://juliabox.com/
  70. Intro to Julia for data science
    https://www.youtube.com/wat­ch?v=SLE0vz85Rqo
  71. Intro to dynamical systems in Julia
    https://www.youtube.com/wat­ch?v=13hqE_1a158