Obsah
1. Specifikace řezu tabulkou v programové smyčce for-each
2. Vliv použití záporného horního indexu při řezu tabulkou
3. Explicitní krok specifikovaný při řezu tabulkou
4. Počítaná programová smyčka typu for ve funkci hodnoty
5. Realizace filtru programovou smyčkou typu for
6. Vrácení hodnot generovaných smyčkou for z funkce
7. Nepatrně zjednodušený zápis programové smyčky typu while
8. Objektově orientované programování v jazyce Moonscript
9. Deklarace třídy s konstruktorem, přístup k atributům objektu
10. Zjednodušený přístup k atributům objektů pomocí operátoru @
11. Volání metod objektu s využitím operátoru \
12. Metody bez parametrů a s jednopříkazovým tělem
13. Předání parametrů konstruktoru objektu
14. Volání metod přímo z konstruktoru
15. Použití programové konstrukce with
18. Příloha: zápis řezu (slice) v různých programovacích jazycích
19. Repositář s demonstračními příklady
1. Specifikace řezu tabulkou v programové smyčce for-each
Již minule jsme se v kapitole o generátorové notaci seznamu (list comprehension) zmínili o možnosti použít pouze vybrané prvky ze zdrojového seznamu (resp. v terminologii jazyka Lua z tabulky), a to s využitím takzvaných řezů (slice), které můžeme v podobné podobě znát například z Pythonu, z jazyka Go popř. z programovacího jazyka Rust (viz též přílohu v osmnácté kapitole). V případě Moonscriptu není možné řez použít v běžných výrazech (což je poměrně velké omezení), ovšem například ho můžeme zapsat v programové smyčce typu for-each, kterou lze mj. zkonstruovat i takto:
-- -- Skript zapsaný v jazyce Moonscript -- items = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10} for item in *items[2,8] print item
Transpilace takto zapsané programové smyčky do jazyka Lua naznačuje způsob převodu řezu na běžnou počítanou smyčku:
-- -- Skript transpilovaný do jazyka Lua -- local items = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 } local _max_0 = 8 for _index_0 = 2, _max_0 < 0 and #items + _max_0 or _max_0 do local item = items[_index_0] print(item) end
Po spuštění tohoto demonstračního příkladu se vypíšou hodnoty od 2 do 8:
2 3 4 5 6 7 8
V případě, že se vynechá první index, dosadí se namísto něj automaticky jednička (číslování prvků v Moonscriptu začíná od jedničky):
-- -- Skript zapsaný v jazyce Moonscript -- items = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10} for item in *items[,8] print item
Opět si uveďme způsob transpilace do jazyka Lua:
-- -- Skript transpilovaný do jazyka Lua -- local items = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 } local _max_0 = 8 for _index_0 = 1, _max_0 < 0 and #items + _max_0 or _max_0 do local item = items[_index_0] print(item) end
Výsledek je v tomto případě očekávatelný:
1 2 3 4 5 6 7 8
Vynechat je ovšem možné i druhý index. V tomto případě se namísto něho dosadí délka pole/tabulky:
-- -- Skript zapsaný v jazyce Moonscript -- items = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10} for item in *items[4,] print item
Transpřeklad předchozí programové smyčky tak, že horní mezí bude skutečně délka tabulky, si můžeme snadno ověřit – viz zvýrazněnou část kódu:
-- -- Skript transpilovaný do jazyka Lua -- local items = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 } for _index_0 = 4, #items do local item = items[_index_0] print(item) end
Výsledek, který po spuštění předchozího skriptu získáme, bude vypadat následovně:
4 5 6 7 8 9 10
2. Vliv použití záporného horního indexu při řezu tabulkou
Horní index je možné zapsat formou záporného čísla. V tomto případě se počítá od konce seznamu/tabulky, nikoli od jejího začátku. Ostatně si můžeme toto chování velmi snadno ověřit:
-- -- Skript zapsaný v jazyce Moonscript -- items = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10} for item in *items[3,-3] print item
Implementace při transpilaci do jazyka Lua je přímočará a vlastně ani nevyžaduje žádné další kroky v porovnání s předchozími demonstračními příklady:
-- -- Skript transpilovaný do jazyka Lua -- local items = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 } local _max_0 = -3 for _index_0 = 3, _max_0 < 0 and #items + _max_0 or _max_0 do local item = items[_index_0] print(item) end
Je zde použita podmínka zapsaná pomocí and-or, kterou lze snadno dešifrovat pro kladnou i zápornou hodnotu max a seznamu délky deset prvků:
max | max < 0 | #items + max | max < 0 and #items + max or max | Poznámka |
---|---|---|---|---|
+5 | false | 15 | 5 | podmínka nesplněna → vyhodnotí se „větev“ za or |
–4 | true | 6 | 6 | podmínka splněna → vyhodnotí se větev za and |
Výsledkem po spuštění předchozího příkladu tedy bude sekvence hodnot:
3 4 5 6 7
3. Explicitní krok specifikovaný při řezu tabulkou
Mnoho programovacích jazyků u řezů podporuje i určení kroku mezi prvky. I tuto konstrukci jazyk Moonscript podporuje, takže si ji můžeme otestovat. V následujícím demonstračním příkladu se řezem vyberou všechny prvky od začátku do konce seznamu, ovšem s krokem 2 (tedy každý druhý prvek):
-- -- Skript zapsaný v jazyce Moonscript -- items = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10} for item in *items[,,2] print item
V takto jednoduchém příkladu je transpilace do jazyka Lua velmi přímočará, protože krok podporuje i jazyk Lua:
-- -- Skript transpilovaný do jazyka Lua -- local items = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 } for _index_0 = 1, #items, 2 do local item = items[_index_0] print(item) end
Výsledek získaný po spuštění tohoto skriptu:
1 3 5 7 9
Programové smyčky s jediným příkazem v těle lze zapsat na jediný programový řádek, ovšem v tomto případě je nutné přidat klíčové slovo do:
-- -- Skript zapsaný v jazyce Moonscript -- items = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10} for item in *items[,,2] do print item
Transpřeklad tohoto skriptu do programovacího jazyka Lua je přímočarý:
-- -- Skript transpilovaný do jazyka Lua -- local items = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 } for _index_0 = 1, #items, 2 do local item = items[_index_0] print(item) end
4. Počítaná programová smyčka typu for ve funkci hodnoty
Již v úvodním článku o programovacím jazyce Moonscript jsme si řekli, že většina konstrukcí v tomto jazyku je ve skutečnosti hodnotou, kterou je možné dále zpracovat. Výjimkou není ani smyčka for popř. smyčka typu for-each, která vrací hodnoty získané v každé iteraci. Můžeme si to snadno ukázat na příkladu počítané smyčky, která vrátí deset hodnot získaných vyhodnocením zlomků 1/1, 1/2, 1/3 až 1/10. Povšimněte si, že tělo smyčky je tvořeno pouze jediným výrazem:
-- -- Skript zapsaný v jazyce Moonscript -- r = for i=1,10 1/i for item in *r do print item
Zdánlivě triviální jednořádkový zápis je transformován do deseti řádků v jazyce Lua, což ukazuje, jak sémanticky silný Moonscript je:
-- -- Skript transpilovaný do jazyka Lua -- local r do local _accum_0 = { } local _len_0 = 1 for i = 1, 10 do _accum_0[_len_0] = 1 / i _len_0 = _len_0 + 1 end r = _accum_0 end for _index_0 = 1, #r do local item = r[_index_0] print(item) end
5. Realizace filtru programovou smyčkou typu for
V programových smyčkách implementovaných (nejenom) v jazyce Moonscript je možné použít konstrukci continue, která slouží k předčasnému ukončení jedné iterace. V případě, že je programová smyčka for použita jako hodnota, má continue ještě jeden důležitý význam – prvek, který by měl být v rámci dané iterace vypočítán, není ve výsledku použit. Toto chování je možné využít při tvorbě filtrů – ve smyčce generujeme hodnoty prvků seznamu nebo slovníku, ovšem pro některé vstupní hodnoty budou prvky vyfiltrovány:
-- -- Skript zapsaný v jazyce Moonscript -- r = for i=1,10 if i >= 4 and i <= 7 continue i*2 for item in *r do print item
Předchozí zápis vytvoří seznam s celočíselnými hodnotami 1 až 10, ovšem bez prvků s hodnotami 4, 5, 6 a 7:
1 2 3 8 9 10
A takto bude vypadat transpřeklad předchozího skriptu do programovacího jazyka Lua:
-- -- Skript transpilovaný do jazyka Lua -- local r do local _accum_0 = { } local _len_0 = 1 for i = 1, 10 do local _continue_0 = false repeat if i >= 4 and i <= 7 then _continue_0 = true break end local _value_0 = i * 2 _accum_0[_len_0] = _value_0 _len_0 = _len_0 + 1 _continue_0 = true until true if not _continue_0 then break end end r = _accum_0 end for _index_0 = 1, #r do local item = r[_index_0] print(item) end
6. Vrácení hodnot generovaných smyčkou for z funkce
Víme již, že smyčky for mohou vracet hodnotu – seznam nebo slovník. Také již víme, že poslední výraz ve funkci je implicitně použit jako návratová hodnota dané funkce. Obě zmíněné vlastnosti by měly vést k tomu, že pokud v těle funkce použijeme smyčku for, bude z funkce implicitně vrácen seznam nebo slovník získaný z iteračních cyklů této smyčky. Ve skutečnosti tomu tak ovšem není a to z toho důvodu, že tvorba návratové hodnoty je relativně složitá/pomalá a mnohdy se tato hodnota zrovna v případě smyček nepoužije (smyčky bývají použity imperativně). Proto je nutné v tomto případě (a jedná se o jediný případ) explicitně použít konstrukci return:
-- -- Skript zapsaný v jazyce Moonscript -- f1 = -> for i=1,10 do i f2 = -> return for i=1,10 do i print f1! print f2!
Povšimněte si, jak zcela odlišným způsobem jsou transpilovány funkce f1 a f2:
-- -- Skript transpilovaný do jazyka Lua -- local f1 f1 = function() for i = 1, 10 do local _ = i end end local f2 f2 = function() return (function() local _accum_0 = { } local _len_0 = 1 for i = 1, 10 do _accum_0[_len_0] = i _len_0 = _len_0 + 1 end return _accum_0 end)() end print(f1()) return print(f2())
7. Nepatrně zjednodušený zápis programové smyčky typu while
Jen pro úplnost se zmiňme o nepatrně jednodušším způsobu zápisu programové smyčky typu while. V jazyce Moonscript není nutné používat klíčové slovo do ani smyčku ukončovat klíčovým slovem end, takže je možné použít následující styl zápisu:
-- -- Skript zapsaný v jazyce Moonscript -- i = 0 while i <= 10 print i i += 1
Transpřeklad tohoto skriptu do programovacího jazyka Lua je v tomto případě přímočarý:
-- -- Skript transpilovaný do jazyka Lua -- local i = 0 while i <= 10 do print(i) i = i + 1 end
8. Objektově orientované programování v jazyce Moonscript
Minule jsme se zmínili o způsobu tvorby skriptů používajících OOP techniky přímo v jazyce Lua. Připomeňme si, že samotný programovací jazyk Lua sice nenabízí pro deklaraci tříd a objektů vlastní syntaxi, ale to neznamená, že by objektově orientované programování nebylo možné. Objekty je totiž možné vytvářet buď na základě uzávěrů (closures) při jejichž použití jsou atributy i metody objektu „zabaleny“ právě v uzávěru (ostatně stejný princip je využitý i v některých funkcionálních jazycích), a/nebo lze využít druhého způsobu založeného na asociativních polích a metatabulkách a metametodách. Tvorba objektů je pak ze sémantického hlediska podobná technice používané v původním JavaScriptu, který byl inspirovaný jazykem Self a takzvaným prototypováním.
Ukazovali jsme si i příklad jednoduché třídy nazvané Account s definicí atributu balance, s konstruktorem a taktéž s dvojicí metod nazvaných withdraw a deposit (každá přitom používá nepatrně odlišný způsob zápisu):
Account = {balance = 0} function Account:new(o) -- create object if user does not provide one o = o or {} setmetatable(o, self) self.__index = self return o end function Account.withdraw(self, value) self.balance = self.balance - value end function Account:deposit(value) self.balance = self.balance + value end local a = Account:new{balance=0} local b = Account:new{balance=50} print("account A", a.balance) print("account B", b.balance) a:withdraw(100.00) b:withdraw(100.00) print("account A", a.balance) print("account B", b.balance) a:deposit(200.00) b:deposit(200.00) print("account A", a.balance) print("account B", b.balance)
Předchozí příklad využíval triku spočívajícího v modifikaci metatabulky. Programovací jazyk Moonscript naproti tomu zavádí zcela odlišný způsob deklarace tříd i metod; liší se i přístup k atributům a volání metod.
9. Deklarace třídy s konstruktorem, přístup k atributům objektu
Ukažme si nyní, jak se deklarují třídy v jazyce Moonscript. Vytvoříme třídu pojmenovanou Customer. Tato třída bude mít konstruktor, který nastaví (automaticky vytvořené) atributy name a surname na hodnoty „N/A“. Dále zavoláme konstruktor, čímž se vytvoří instance této třídy a zobrazíme hodnoty obou atributů objektu:
-- -- Skript zapsaný v jazyce Moonscript -- class Customer new: => self.name = "N/A" self.surname = "N/A" c = Customer! print c.name print c.surname
Překlad tohoto demonstračního příkladu do jazyka Lua je již dosti dlouhý – zde je jasně patrná větší úroveň abstrakce Moonscriptu:
-- -- Skript transpilovaný do jazyka Lua -- local Customer do local _class_0 local _base_0 = { } _base_0.__index = _base_0 _class_0 = setmetatable({ __init = function(self) self.name = "N/A" self.surname = "N/A" end, __base = _base_0, __name = "Customer" }, { __index = _base_0, __call = function(cls, ...) local _self_0 = setmetatable({}, _base_0) cls.__init(_self_0, ...) return _self_0 end }) _base_0.__class = _class_0 Customer = _class_0 end local c = Customer() print(c.name) return print(c.surname)
10. Zjednodušený přístup k atributům objektů pomocí operátoru @
V předchozím demonstračním příkladu se k atributům objektu přistupovalo s využitím standardní tečkové notace, tedy následovně:
new: => self.name = "N/A" self.surname = "N/A"
Uvnitř deklarace třídy popř. deklarace metod je však možné použít i nový operátor @, který nevyžaduje zápis self.. Jedná se o nepovinnou syntaxi, která je však užitečná, neboť přístup k atributu opticky zvýrazní. Následuje příklad použití tohoto „syntaktického cukru“:
-- -- Skript zapsaný v jazyce Moonscript -- class Customer new: => @name = "N/A" @surname = "N/A" c = Customer! print c.name print c.surname
Transpřeklad do jazyka Lua je naprosto shodný s předchozím příkladem, o čemž se můžeme velmi snadno přesvědčit:
-- -- Skript transpilovaný do jazyka Lua -- local Customer do local _class_0 local _base_0 = { } _base_0.__index = _base_0 _class_0 = setmetatable({ __init = function(self) self.name = "N/A" self.surname = "N/A" end, __base = _base_0, __name = "Customer" }, { __index = _base_0, __call = function(cls, ...) local _self_0 = setmetatable({}, _base_0) cls.__init(_self_0, ...) return _self_0 end }) _base_0.__class = _class_0 Customer = _class_0 end local c = Customer() print(c.name) return print(c.surname)
11. Volání metod objektu s využitím operátoru \
Dostáváme se k poněkud kontroverzní syntaxi použité v jazyku Moonscript. Jedná se o zápis volání metod. Nejdříve si ukažme způsob deklarace běžných metod:
set_name: (name) => @name = name set_surname: (surname) => @surname = surname
Tyto metody se nevolají „tečkovou notací“, ale s využitím operátoru \:
c = Customer! c\set_name "Foo" c\set_surname "Bar"
Úplný skript s deklarací třídy s dvojicí metod může vypadat následovně:
-- -- Skript zapsaný v jazyce Moonscript -- class Customer new: => @name = "N/A" @surname = "N/A" set_name: (name) => @name = name set_surname: (surname) => @surname = surname c = Customer! print c.name print c.surname c\set_name "Foo" c\set_surname "Bar" print c.name print c.surname
Z transpilovaného kódu je patrné, že se volání metod přeložilo na c:set_name(…) a c:set_surname(…):
-- -- Skript transpilovaný do jazyka Lua -- local Customer do local _class_0 local _base_0 = { set_name = function(self, name) self.name = name end, set_surname = function(self, surname) self.surname = surname end } _base_0.__index = _base_0 _class_0 = setmetatable({ __init = function(self) self.name = "N/A" self.surname = "N/A" end, __base = _base_0, __name = "Customer" }, { __index = _base_0, __call = function(cls, ...) local _self_0 = setmetatable({}, _base_0) cls.__init(_self_0, ...) return _self_0 end }) _base_0.__class = _class_0 Customer = _class_0 end local c = Customer() print(c.name) print(c.surname) c:set_name("Foo") c:set_surname("Bar") print(c.name) return print(c.surname)
12. Metody bez parametrů a s jednopříkazovým tělem
Typickým příkladem metody bez parametrů jsou gettery (pokud je tedy vůbec budete chtít používat). Takové metody nemají žádné parametry a většinou obsahují pouze konstrukci určenou pro vrácení hodnoty atributu. Takové metody je možné v jazyce Moonscript psát skutečně minimalisticky:
get_name: => @name get_surname: => @surname
Pochopitelně je možné zvolit i zápis celé metody na jediném řádku:
get_name: => @name get_surname: => @surname
Následuje příklad použití takto deklarovaných metod:
-- -- Skript zapsaný v jazyce Moonscript -- class Customer new: => @name = "N/A" @surname = "N/A" set_name: (name) => @name = name set_surname: (surname) => @surname = surname get_name: => @name get_surname: => @surname c = Customer! print c\get_name! print c\get_surname! c\set_name "Foo" c\set_surname "Bar" print c\get_name! print c\get_surname!
Transpřeklad do programovacího jazyka Lua:
-- -- Skript transpilovaný do jazyka Lua -- local Customer do local _class_0 local _base_0 = { set_name = function(self, name) self.name = name end, set_surname = function(self, surname) self.surname = surname end, get_name = function(self) return self.name end, get_surname = function(self) return self.surname end } _base_0.__index = _base_0 _class_0 = setmetatable({ __init = function(self) self.name = "N/A" self.surname = "N/A" end, __base = _base_0, __name = "Customer" }, { __index = _base_0, __call = function(cls, ...) local _self_0 = setmetatable({}, _base_0) cls.__init(_self_0, ...) return _self_0 end }) _base_0.__class = _class_0 Customer = _class_0 end local c = Customer() print(c:get_name()) print(c:get_surname()) c:set_name("Foo") c:set_surname("Bar") print(c:get_name()) return print(c:get_surname())
13. Předání parametrů konstruktoru objektu
Konstruktor, který je realizován metodou nazvanou new, se chová podobně jako běžná metoda, tedy až na jediný rozdíl – vrací instanci právě vytvořeného objektu a nikoli uživatelem specifikovanou hodnotu. Ovšem v jiných ohledech se jedná o běžnou metodu, která tedy může akceptovat parametry. V následující ukázce je konstruktor upraven tak, aby akceptoval dva parametry. Taktéž je ukázán způsob volání takového konstruktoru:
-- -- Skript zapsaný v jazyce Moonscript -- class Customer new: (name, surname) => @name = name @surname = surname set_name: (name) => @name = name set_surname: (surname) => @surname = surname get_name: => @name get_surname: => @surname c = Customer "foo", "bar" print c\get_name! print c\get_surname! c\set_name "FOO" c\set_surname "BAR" print c\get_name! print c\get_surname!
Transpilace tohoto krátkého skriptu do jazyka Lua je již dosti sáhodlouhá:
-- -- Skript transpilovaný do jazyka Lua -- local Customer do local _class_0 local _base_0 = { set_name = function(self, name) self.name = name end, set_surname = function(self, surname) self.surname = surname end, get_name = function(self) return self.name end, get_surname = function(self) return self.surname end } _base_0.__index = _base_0 _class_0 = setmetatable({ __init = function(self, name, surname) self.name = name self.surname = surname end, __base = _base_0, __name = "Customer" }, { __index = _base_0, __call = function(cls, ...) local _self_0 = setmetatable({}, _base_0) cls.__init(_self_0, ...) return _self_0 end }) _base_0.__class = _class_0 Customer = _class_0 end local c = Customer("foo", "bar") print(c:get_name()) print(c:get_surname()) c:set_name("FOO") c:set_surname("BAR") print(c:get_name()) return print(c:get_surname())
14. Volání metod přímo z konstruktoru
Často je nutné z konstruktoru nebo z jiných metod volat další metody toho samého objektu. Vzhledem k tomu, že Moonscript je jazykem s podporou běžných funkcí, je nutné nějakým způsobem odlišit volání běžné funkce od volání metody (Java tento problém nemá). K tomuto účelu slouží opět operátor @, kterým lze uvnitř nějaké metody (včetně konstruktoru) zajistit volání metody jiné. Pokud tedy budeme chtít z konstruktoru new volat settery, lze to zajistit jednoduše:
-- -- Skript zapsaný v jazyce Moonscript -- class Customer new: (name, surname) => @set_name(name) @set_surname(surname) set_name: (name) => @name = name set_surname: (surname) => @surname = surname get_name: => @name get_surname: => @surname c = Customer "foo", "bar" print c\get_name! print c\get_surname! c\set_name "FOO" c\set_surname "BAR" print c\get_name! print c\get_surname!
S tímto překladem do jazyka Lua:
-- -- Skript transpilovaný do jazyka Lua -- local Customer do local _class_0 local _base_0 = { set_name = function(self, name) self.name = name end, set_surname = function(self, surname) self.surname = surname end, get_name = function(self) return self.name end, get_surname = function(self) return self.surname end } _base_0.__index = _base_0 _class_0 = setmetatable({ __init = function(self, name, surname) self:set_name(name) return self:set_surname(surname) end, __base = _base_0, __name = "Customer" }, { __index = _base_0, __call = function(cls, ...) local _self_0 = setmetatable({}, _base_0) cls.__init(_self_0, ...) return _self_0 end }) _base_0.__class = _class_0 Customer = _class_0 end local c = Customer("foo", "bar") print(c:get_name()) print(c:get_surname()) c:set_name("FOO") c:set_surname("BAR") print(c:get_name()) return print(c:get_surname())
Samozřejmě není nutné při volání metod používat kulaté závorky:
-- -- Skript zapsaný v jazyce Moonscript -- class Customer new: (name, surname) => @set_name name @set_surname surname set_name: (name) => @name = name set_surname: (surname) => @surname = surname get_name: => @name get_surname: => @surname c = Customer "foo", "bar" print c\get_name! print c\get_surname! c\set_name "FOO" c\set_surname "BAR" print c\get_name! print c\get_surname!
Překlad bude naprosto totožný s předchozím příkladem:
-- -- Skript transpilovaný do jazyka Lua -- local Customer do local _class_0 local _base_0 = { set_name = function(self, name) self.name = name end, set_surname = function(self, surname) self.surname = surname end, get_name = function(self) return self.name end, get_surname = function(self) return self.surname end } _base_0.__index = _base_0 _class_0 = setmetatable({ __init = function(self, name, surname) self:set_name(name) return self:set_surname(surname) end, __base = _base_0, __name = "Customer" }, { __index = _base_0, __call = function(cls, ...) local _self_0 = setmetatable({}, _base_0) cls.__init(_self_0, ...) return _self_0 end }) _base_0.__class = _class_0 Customer = _class_0 end local c = Customer("foo", "bar") print(c:get_name()) print(c:get_surname()) c:set_name("FOO") c:set_surname("BAR") print(c:get_name()) return print(c:get_surname())
15. Použití programové konstrukce with
Pokud se v nějakém bloku kódu často volají metody určitého objektu, lze tento blok zjednodušit použitím programové konstrukce with. Namísto:
c = Customer "foo", "bar" print c\get_name! print c\get_surname! c\set_name "FOO" c\set_surname "BAR" print c\get_name! print c\get_surname!
lze psát:
with Customer "foo", "bar" print \get_name! print \get_surname! \set_name "FOO" \set_surname "BAR" print \get_name! print \get_surname!
Opět se pochopitelně podíváme na ucelený spustitelný příklad:
-- -- Skript zapsaný v jazyce Moonscript -- class Customer new: (name, surname) => @set_name name @set_surname surname set_name: (name) => @name = name set_surname: (surname) => @surname = surname get_name: => @name get_surname: => @surname with Customer "foo", "bar" print \get_name! print \get_surname! \set_name "FOO" \set_surname "BAR" print \get_name! print \get_surname!
I na způsob jeho transpilace do programovacího jazyka Lua:
-- -- Skript transpilovaný do jazyka Lua -- local Customer do local _class_0 local _base_0 = { set_name = function(self, name) self.name = name end, set_surname = function(self, surname) self.surname = surname end, get_name = function(self) return self.name end, get_surname = function(self) return self.surname end } _base_0.__index = _base_0 _class_0 = setmetatable({ __init = function(self, name, surname) self:set_name(name) return self:set_surname(surname) end, __base = _base_0, __name = "Customer" }, { __index = _base_0, __call = function(cls, ...) local _self_0 = setmetatable({}, _base_0) cls.__init(_self_0, ...) return _self_0 end }) _base_0.__class = _class_0 Customer = _class_0 end do local _with_0 = Customer("foo", "bar") print(_with_0:get_name()) print(_with_0:get_surname()) _with_0:set_name("FOO") _with_0:set_surname("BAR") print(_with_0:get_name()) print(_with_0:get_surname()) return _with_0 end
16. Blok do
Blok do se v jazyce Moonscript používá prakticky stejným způsobem jako v jazyce Lua, ovšem s tím (očekávaným) rozdílem, že poslední výraz je z tohoto bloku vrácen a je ho možné například přiřadit do proměnné:
-- -- Skript zapsaný v jazyce Moonscript -- z = do x = 10 y = 20 x + y print z
Povšimněte si, že proměnné x a y jsou lokální skutečně jen v rámci bloku do:
-- -- Skript transpilovaný do jazyka Lua -- local z do local x = 10 local y = 20 z = x + y end return print(z)
17. Destructuring
V některých programovacích jazycích se setkáme s termínem destructuring, kterým se většinou označuje „rozložení“ nějaké datové struktury na jednotlivé prvky a přiřazení těchto položek do proměnných (viz například jazyky Rust, Python či Clojure). Destructuring lze využít i v Moonscriptu, a to například pro uložení položek z tabulky do dvou proměnných:
foo = {1,2} {x,y} = foo
V praxi, například při práci s deserializovaným JSONem, se setkáme i s destructuringem vnořených položek objektů:
obj = { numbers: {1,2,3,4} } {numbers: {first, second}} = obj
V tomto případě jsme získali hodnoty prvních dvou prvků z vnořené tabulky numbers a uložili jsme je do proměnných first a second.
Celý skript ukazující dvě možnosti destructuringu, lze v Moonscriptu zapsat následovně:
-- -- Skript zapsaný v jazyce Moonscript -- foo = {1,2} {x,y} = foo print x, y obj = { numbers: {1,2,3,4} } {numbers: {first, second}} = obj print first, second
Z transpilovaného kódu je patrné, jak je destructuring realizován:
-- -- Skript transpilovaný do jazyka Lua -- local foo = { 1, 2 } local x, y x, y = foo[1], foo[2] print(x, y) local obj = { numbers = { 1, 2, 3, 4 } } local first, second first, second = obj.numbers[1], obj.numbers[2] return print(first, second)
18. Příloha: zápis řezu (slice) v různých programovacích jazycích
Řezy neboli slices jsou podporovány v mnoha programovacích jazycích. Syntaxe jejich zápisu se liší, stejně jako chápání (sémantika) horního indexu (tedy zda má být prvek s tímto indexem součástí řezu či nikoli). Následující tabulka ukazuje zápis řezů ve vybraných programovacích jazycích:
Syntaxe zápisu | Programovací jazyk(y) |
---|---|
name[první,poslední] | Moonscript |
name[první:poslední] | ALGOL 68, Julia |
name[první:poslední+1:krok] | Python |
name[první:poslední+1] | Go |
name[první..poslední] | Pascal, Object Pascal, Delphi, Nim |
$name[první..poslední] | Windows PowerShell |
@name[první..poslední] | Perl |
name[první..poslední] | Ruby |
name[první…poslední+1] | Ruby |
name[první, délka] | Ruby |
name(první..poslední) | Ada |
name(první:poslední) | Fortran, GNU Octave, MATLAB |
name[[první;;poslední;;krok]] | Mathematica, Wolfram Language |
name.slice(první, poslední+1) | Haxe, JavaScript, Scala |
name[první..<poslední+1] | Swift |
name[první…poslední] | Swift |
name[první..poslední+1] | D, C# |
name[první..poslední+1] | Rust |
name[první..=poslední] | Rust |
name[první:poslední+1] | Cobra |
name.[první..krok..poslední] | F# |
array_slice(proměnná, první, délka) | PHP |
19. Repositář s demonstračními příklady
20. Odkazy na Internetu
- Stránky projektu Moonscript
https://moonscript.org/ - Moonscript na GitHubu
https://github.com/leafo/moonscript - MoonScript online compiler
https://moonscript.org/compiler/ - Vydání Moonscriptu
https://github.com/leafo/moonscript/releases - Moonscript-vim
https://github.com/leafo/moonscript-vim - Moonscript Examples
https://github.com/leafo/moonscript/wiki/Moonscript-Examples - CoffeeScript
https://coffeescript.org/ - CoffeeScript na Wikipedii
https://en.wikipedia.org/wiki/CoffeeScript - CoffeeScript: řádně oslazený JavaScript
https://zdrojak.cz/clanky/coffeescript-radne-oslazeny-javascript/ - CoffeeScript: druhá dávka steroidů pro vaše skripty
https://zdrojak.cz/clanky/coffeescript-druha-davka-steroidu-pro-vase-skripty/ - Why CoffeeScript is still alive
https://codeburst.io/why-coffeescript-is-still-alive-aeb369b91b85 - The CoffeeScript Wiki
https://github.com/jashkenas/coffeescript/wiki - CoffeeScript In The Wild
https://github.com/jashkenas/coffeescript/wiki/In-The-Wild - How CoffeeScript Got Forgotten
https://betterprogramming.pub/how-coffeescript-got-forgotten-812328225987 - ULua: Universal Lua Distribution
https://ulua.io/index.html - LuaRocks
https://luarocks.org/ - Awesome Lua – A curated list of quality Lua packages and resources.
https://github.com/LewisJEllis/awesome-lua - LuaJIT
https://luajit.org/ - Running LuaJIT
https://luajit.org/running.html - LuaJIT na GitHubu
https://github.com/luajit - Lua Implementations
http://lua-users.org/wiki/LuaImplementations - Coconut: funkcionální jazyk s pattern matchingem kompatibilní s Pythonem
https://www.root.cz/clanky/coconut-funkcionalni-jazyk-s-pattern-matchingem-kompatibilni-s-pythonem/ - Coconut aneb funkcionální nadstavba nad Pythonem (2.část)
https://www.root.cz/clanky/coconut-aneb-funkcionalni-nadstavba-nad-pythonem-2-cast/ - Coconut: Simple, elegant, Pythonic functional programming
http://coconut-lang.org/ - coconut 1.1.0 (Python package index)
https://pypi.python.org/pypi/coconut/1.1.0 - Coconut Tutorial
http://coconut.readthedocs.io/en/master/HELP.html - Coconut FAQ
http://coconut.readthedocs.io/en/master/FAQ.html - Coconut Documentation
http://coconut.readthedocs.io/en/master/DOCS.html - Coconut na Redditu
https://www.reddit.com/r/Python/comments/4owzu7/coconut_functional_programming_in_python/ - Repositář na GitHubu
https://github.com/evhub/coconut - patterns
https://github.com/Suor/patterns - Source-to-source compiler
https://en.wikipedia.org/wiki/Source-to-source_compiler - The Lua VM, on the Web
https://kripken.github.io/lua.vm.js/lua.vm.js.html - Lua.vm.js REPL
https://kripken.github.io/lua.vm.js/repl.html - lua2js
https://www.npmjs.com/package/lua2js - Wisp na GitHubu
https://github.com/Gozala/wisp - Wisp playground
http://www.jeditoolkit.com/try-wisp/ - REPL v prohlížeči
http://www.jeditoolkit.com/interactivate-wisp/ - Minification (programming)
https://en.wikipedia.org/wiki/Minification_(programming) - Roblox
https://en.wikipedia.org/wiki/Roblox - Category:Lua (programming language)-scriptable game engines
https://en.wikipedia.org/wiki/Category:Lua_(programming_language)-scriptable_game_engines - Goodbye Lua (shrnutí následujícího článku)
https://www.reddit.com/r/lua/comments/4ld6ao/goodbye_lua/ - Goodbye, Lua
https://realmensch.org/2016/05/28/goodbye-lua/ - 6th Edition – ECMAScript 2015
https://en.wikipedia.org/wiki/ECMAScript#6th_Edition_%E2%80%93_ECMAScript_2015 - Assignment (computer science)
https://en.wikipedia.org/wiki/Assignment_(computer_science) - Destructuring in Clojure
https://clojure.org/guides/destructuring - Should Array Index Start at 0 or 1?
http://xahlee.info/comp/comp_lang_array_index_start0_or1.html - Programming Languages where indices start from 1 (NOT 0)
https://iq.opengenus.org/array-indices-start-from-1/ - Comparison of programming languages (array)
https://en.wikipedia.org/wiki/Comparison_of_programming_languages_(array)#Indexing