Matzova keynote na RubyConf 2007
Tento článek shrnuje Matzovu (tvůrce Ruby) keynote na RubyConf 2007. Dříve jsem psal o prvním a druhém dni.
Matz se na začátku rozpovídal na téma "Zaleží na použitém jazyce?" a začal s tím, že přeci ne. Že všechny (běžné) jazyky jsou Turing-kompletní a tudíž mají stejnou sílu. A že Twitter zvýšil výkonnost desetinásobně bez změny platformy, tudíž na jazyce nezáleží. Nebo ano? Ale jistě, důležitý je podle něj přístup. Ruby má příjemnou syntaxi a je kolem něj velmi entuziastická komunita a to znamená mnoho. Zde byla vhodná chvíle na úklon a poděkovaní všem v sále za jejich nadšení. Související poznámkou bylo, že 42% výdělku ThoughtWorks v USA pochází z Ruby projektů (o tom jsme se zde již zmiňovali) a že to prý jejich šéfovi pěkně zavařil, protože málokdo z jeho firmy chce dělat cokoliv jiného než Ruby. Jak říká Martin Fowler "There is business value in fun". Na konec první části přednášky Matz úkazal jakousi vtipnou tabulku vyjadřující poměr láska/nenávist pro různé jazyky vycházející z prý reálné ankety, ve které byli programátoři dotázáni, jestli daný programovací jazyk milují nebo nenávidí. Ruby vyšlo jako spolehlivý vítěz s poměrem 7,18, následoval Perl s 4,53 a Python s 4,35. Bral jsem to spíš jako žert, Ruby se pořádně rozšiřuje teprve v poslední době, a tak většina jeho programátorů si ho spíše sama vybrala, než že by jim byl "přidělen" zaměstnavatelem. Plus další důvody. A to byl konec sektářského úvodu.
Druhá část se věnovala nové verze Ruby - 1.9. Ta prý vyjde o letošních Vánocích, i když nebude tak stabilní, jak si autoři původně představovali. Bude obsahovat vlastnosti nekompatibilní s verzemi 1.8.x, tři z nich jsou podle Matze zásadní:
- Odlišná práce s argumenty bloku. Argument bloku již nemůže být globální proměnná ani členská proměnná objektu. Tedy žádné
|$global| nebo |object.member|. Proměnné bloku také budou zastiňovat lokalní proměnné vně bloku, tj. x uvnitř bloku je jiné, než x vně:
irb(main):022:0> x = 10 => 10 irb(main):023:0> [1,2,3].each {|i| x = i} => [1, 2, 3] irb(main):024:0> x => 3Takhle to fuguje nyní, v 1.9 už x zůstane 10. Tohle mi přijde jako dost marginální změna, protože v podstatě byly odstraněny možnosti, které žádný rozumný programátor nepoužije.. - Řetězce již neobsahují Enumerable. Řetězce tedy již nepůjde iterovat metodou each. Ta ve stávající verzi iteruje přes jeho řádky, což evidentně nejen mně přišlo trochu neintuitivní. Matz podotkl, že vlastně není jasné, přes co by měla tato metoda iterovat, a proto místo ní přibydou metody lines, chars, bytes, které budou vracet příslušná pole (které se dají bez problému iterovat přes each, tj. "česky".chars.each pojede po jednotlivých znacích).
- Řetězce vědí o svém kódování a prvky řetězce vrací znaky. Řetězce už znají kódování, defaultně tuším UTF-8, ale při různých operacích to půjde předefinovat. Napříkad při otevírání souboru půjde určit, v jakém kódování očekáváme obsah. Související změnou je, že přístup na jednotlivé znaky řetězce bude vracet daný znak (řetězec o délce jedna) a ne jeho ASCII kód, jak je tomu nyní ("ahoj"[1] nevrátí 104, ale "h").
Další nekompatibility jsou prý již nezásadní, Matz rychle ukázal slajd se spoustou změněných metod. Vypíchnuta byla jen neexistence File.exists? ve prospěch File.exist?, protože den předtím si na to někdo stězoval..
Kromě zpětně nekompatibilních změn přibyde i nová funkcionalita. Anonymní (lambda) funkce lze vytvořit novou syntaxí za pomocí "->". Vtipálek Matz ukázal sérii obrázku, ve které se znak lambdy nakláněl a postupně měnil v tuto dvojici znaků, jakože to je podobné.. Nový zápis dělá "->(a, b) {puts a+b}" ekvivalentní s "lambda {|a,b| puts a+b}". Parametry navíc můžou mít výchozí hodnoty. Lambdy půjdou zavolat i s vynecháním jména metody call: lambda.(1,2) bude stejné jako lambda.call(1, 2).
Přibyly iterátory či enumerátory. Tj. lze si z iterovatelného objektu "vytáhnout" pomocný objekt a iterovat pak přes něj. e = [1, 2, 3].each. Opakovaným voláním e.next pak dostaneme jednotlivé prvky pole. Javisté budou znát. Může se asi někdy hodit. Matz ukázal následujicí kousek kódu:
e1 = [1, 2, 3].each
e2 = [3, 4, 5, 6].each
loop {
p e1.next + e2.next
}
Toto není nekonečná smyčka, normálně to vytiskne postupně 4, 6 a 8. Metoda next totiž vyhodí nějakou výjimku (EndOfLoopException či co), která způsobí vyskočení z cyklu. Nějak se mi to moc nelibí, chování není jasné na první pohled. Taky jsem si myslel, že výjimky se použivají na výjimečné stavy, ne na vyskočení z cyklu. Anyway.
Další podivností je možnost mít povinné argumenty za nepovinnými. Doteď pokud nějaké argumenty byly nepovinné (tj. měly výchozí hodnotu), nešlo za ně přidat žádné povinné. Tj. def method(a, b=1, c=2, d) nebylo povoleno. V Ruby 1.9 je. Jestli se ptáte, jak tedy vlastně budou hodnoty ve volání metody do proměnných přiřazovány, nejste samy. Byl kolem toho v sále docela rozruch. Matz uvedl pár příkladů:
def m(a, b=24, c) m(1,2) a -> 1 b -> 24 c -> 2 def m(1, b=1, c=2, d) m(1, 2, 3) a -> 1 b -> 2 c -> 2 d -> 3
Celkem jsem pochopil, jak si rychle uvědomit, co přijde kam: Nejdřív se přiřadí všechny povinné na začátku, poté všechny povinné na konci a pak se berou zbylé mezi tím a přiřazují se odleva, jak tomu bylo doteď (na které se nedostane, dostanou výchozí hodnotu). Problém je, že i Matzovi kolikrát vteřinu trvalo, než to vymyslel. A to on ten jazyk navrhuje.. Doufám, že nic takového se neobjeví v žádném programu, se kterým přijdu do styku; já sám to nepoužiju určitě. Matz vysvětloval, že je to nutný mezikrok pro pojmenované argumenty (které budou v Ruby 2), což se mi moc nezdá. Že by nešlo tohle zakázat a stejně pojmenované parametry umožnit?
Dalšími změnou je používání nativních vláken (co to znamená poznamenává David Majda v komentáři k minulému článku), odlišné bude také nakládání s členskými proměnnými třídy. Jak odlišné jsme se nedozvěděli, ale našel jsem článek, který mluví nejen o tom, ale zmiňuje a vysvětluje i další připravované změny.
Implementace jazyka se bude jmenovat YARV a nedělal ji Matz (někteří jásají), měla by být znatelně rychlejší a konzumovat o něco méně paměti. Matz vtipkoval, že Rubinius je rychlejší než MRI, JRuby je rychlejší než MRI, IronRuby je rychlejší než MRI a že tedy už byl čas předat implementaci někomu jinému. Někdo se zeptal, jestli množství implementací nemůže Ruby uškodit. Matz říkal, že mnoho jich nebude, protože Ruby je naštěstí těžké naimplementovat. On že to zkusil jednou a již nikdy více.
Závěr patřil filozofování na téma současnost a budoucnost jazyka. V klasickém schématu tragédie - nesmělý začátek -> úspěch -> pýcha -> konflikt/válka -> úpadek - se nacházíme v stadiu úspěch a snad to tak prý nějaký čas zůstane. Prý ať chceme nebo ne (Matz že on ne, ale nedá se nic dělat), Ruby si najde cestu do velkých firem (usuzuje podle "the suits people that are surrounding us"). Na podobné téma jsem shlédnul velmi zajímavou prezentaci Kena Auera z Ruby Hoedown 2007, která srovnává historii Smalltalku s Ruby a vůbec obecně mluví o tom, za jakých podmínek se technologie rozšiřují z pár nadšenců mezi masy. Zajímavé, doporučuji.
1 day later:
3 days later:
"Tohle mi přijde jako dost marginální změna, protože v podstatě byly odstraněny možnosti, které žádný rozumný programátor nepoužije.."
Z pohledu uživatele jazyka marginální, z pohledu vnitřností Ruby naprosto zásadní, protože to mnohé věci pročišťuje.
V gramatice jazyka jsou totiž v 1.8 parametry bloku totéž, co levá strana příkazu přiřazení. Proto tam jdou přiřazovat i globální proměnné, atributy apod. Parametry funkcí jsou něco úplně jiného, tam tyhle opičárny nejdou.
Proč to je takhle špatně vymyšlené netuším, je to typická Matzovina (= zjevně naprosto špatně navržená/implementovaná věc, která je ale trochu pod povrchem, takže se o ní moc neví, díky čemuž Matze všichni oslavují :)
"Nějak se mi to moc nelibí, chování není jasné na první pohled. Taky jsem si myslel, že výjimky se používají na výjimečné stavy, ne na vyskočení z cyklu."
Mě se to taky moc nelíbí. Výjimky v tomto kontextu (ukončení iterace) začal používat Python, od něj se to šíří (minimálně ještě do novějších verzí JavaScriptu).
"Implementace jazyka se bude jmenovat YARV a nedělal ji Matz (někteří jásají)"
Skáču až do stropu ;)
Zcela vážně: Matz není moc dobrý programátor, a to říkám jako člověk, který se v jeho kódu 3/4 roku vrtá skoro každý den.
5 days later: