Snad ani ne. Článek má smysl pouze jako prezentace jednoho nápadu, přičemž úrovní je nesrovnatelný s místním seriálem p. Křivánka, který řídicí struktury též rozebírá.
Autor se zde dopouští mnoha nepřesností, ze kterých podezřívám deformaci jeho mozku z C++ (holt 2 neslučitelné světy) a které dělají dojem, že v tom ještě nemá úplně jasno. Např.:
„Volání má přesně stejný význam jako volání objektových programovacích jazycích hlavního proudu.“ Určitě ne.
„Pokud má metoda jeden argument...“ Jedná se o selektor zprávy.
„Blok kódu (anonymní funkce)“ Je to uzávěra (closure), anon. fce či lambda je něco jiného.
„Ve Smalltalku má třída Boolean dva potomky, singletony True a False.“ Jedináčky jsou až instance, ne třídy.
„Ve Smalltalku je tedy (alespoň na syntaktické úrovni) větvení implementováno pomocí polymorfismu.“ Co má společného syntaxe s polymorfismem???
„pokud je podmínkový blok literálem“ Nepřesné, lépe „uzávěra obsahuje pouze literál“.
„Smalltalk... - místo switch/ case se v běžném programování používá např. dědičnost“ Polymorfismus, dědičnosti netřeba (opět deformace z pseudoOOP?).
„abychom si připadali skoro jako v Céčku nebo v Javě“ To bychom asi neradi.
Jako nápad dodávám doplnění třídní metody
Object>>case
^Case on: self
Za pochvalu stojí na místní poměry nadprůměrný jazyk užitý v článku.
„Pokud má metoda jeden argument...“ Jedná se o selektor zprávy.
Pro doplnění: Metoda je kód navázaný na nějaký objekt (třídu). Selektor je symbol, který odpovídá názvu metody (tedy např. #ifTrue:ifFalse:, nebo #+). Zaslání zprávy objektu ("volání metody") zapouzdřuje selektor metody, aby se vědělo, co volat a argumenty, tedy to co se při volání předává dané metodě. Počet parametrů, které metoda potřebuje (arita), je podle mě nerozlučně svázaný se selektorem, jejich arity si musí odpovídat. Takže původní text mě neurážel, jen bych asi použil spíš slovo "parametr" místo "argument"
„Ve Smalltalku má třída Boolean dva potomky, singletony True a False.“ Jedináčky jsou až instance, ne třídy.
No, asi to tak původní autor nemyslel, ale pro zajímavost, ve Smalltalku jsou i třídy True a False singletony - třída je taky objekt, instance metatřídy, True je jediná instance třídy "True class", False je jediná instance třídy "False class".
5. 8. 2020, 16:14 editováno autorem komentáře
Fór je v tom, že dokud se to bude pořád předhazovat takhle, nedojde nováčkům, že volání a zasílání zprávy jsou 2 odlišné mechanismy, a budou tu dokola padat dotazy, v čem že se to liší, nebo hůře pseudonázory, že je to to samé.
Máte pravdu, to jsem si neuvědomil, ale to platí pro každou třídu, to nemusel autor psát. Mimoto zaměňování tříd a instancí je taky běžným nešvarem.
Tak efekt komentářů, jako jsou ty tvoje, je takový, že snad ani nechci být nováčkem ve světě smalltalku a raději se budu věnovat jiným jazykům.
Přijde mi, že si za malou rozšířenost svých jazyků ti smalltalkisti, haskellisti, ocamlisti atd. můžou z velké části sami tím, jak odpuzují lidi.
Článek je možná v lecčems nepřesný, ale jinak srozumitelný a celkem vyvolává touhu si o Smalltalku přečíst něco víc a možná si v tom zkusit i něco napsat.
Díky za upřesnění pro nás méně znalé. Nicméně za takové články jako je tento jsem taky vděčný. Na současném českém internetu je to vysoký nadstandard a to nejen po jazykové stránce, ale i odborné. Článek je dobře strukturovaný, přímočaře napsaný a srozumitelný i pro lidi, kteří o Smalltalku slyšeli naposledy ve škole, jako já. Velice proto oceňuji možnost si rozšířit obzor... Samozřejmě by bylo fajn, kdyby v něm nebyly vámi uvedené nepřesnosti, ale určitě je lepší přečíst si článek s nepřesnostmi, než žádný...
Dvě Vaše připomínky si snad zaslouží dovysvětlení.
„Blok kódu (anonymní funkce)“ Je to uzávěra (closure), anon. fce či lambda je něco jiného.
Citovaného zjednodušení jsem se dopustil s cílem zachovat plynulost výkladu. Úplně stejného prohřešku se dopouští i heslo o Smaltalku na anglické wikipedii: “A block of code (an anonymous function) ...”
Pro zajímavost dodám, že Smalltalk-80 a jeho přímí následníci měli jednodušší implementaci bloků, které uzávěry nebyly. Implementaci bloků, které jsou uzávěry, vytvořil pro Squeak/Cuis/Pharo Eliot Miranda v roce 2008.
„Ve Smalltalku je tedy (alespoň na syntaktické úrovni) větvení implementováno pomocí polymorfismu.“ Co má společného syntaxe s polymorfismem???
Přestože syntaxe naznačuje užití polymofismu, ve skutečnosti k němu nedochází. Speciální selektory #ifTrue:
a další jsou totiž rozpoznány překladačem a přeloženy pomocí skoků.
O tom se lze snadno přesvědčit, vytvoříme-li metodu
My>>aaa: aBool
^aBool ifTrue: [ 1 ] ifFalse: [ 2 ]
Můžeme se podívat na její bytecode:
33 <10> pushTemp: 0 34 <99> jumpFalse: 37 35 <76> pushConstant: 1 36 <90> jumpTo: 38 37 <77> pushConstant: 2 38 <7C> returnTop
U ostatních Vašich připomínek si nejsem jistý, zda může opravdu dojít k Vámi uvedenému “jinočtení” původního textu.
Děkuji za článek. Jen pár poznámek:
- ve Smalltalku neexistuje volání metod, jen zasílání zpráv objektům
- metoda caseOf: bývá optimalizována v bytekódu, takže ke switch/case má hodně blízko, ale téměř se nepoužívá (v 1,1 milionu řádků Pharo 8 je použita jen 15x). V čistém objektově orientovaném kódu není potřeba.
IMHO se pojem „zasílání zpráv objektům“ používá obvykle v kontextu dynamic dispatch https://en.wikipedia.org/wiki/Dynamic_dispatch
Zatímco pojem „volání metody“ v kontextu static dispatch https://en.wikipedia.org/wiki/Static_dispatch
Viz též diskuze https://forum.root.cz/index.php?topic=11249.msg132240#msg132240
To, zda je zpráva objektem, je zde zcela nepodstatné, to podstatné, co jste nenapsal, je, že zpráva sama o sobě neurčuje, co se bude vykonávat, to si určuje sám až přijímající objekt. Neboli volání říká „dělej toto (v tomto kontextu)“, zpráva pouze říká adresátovi (= objektu) „hele, mám tu pro tebe nějakou informaci, dělej si s tím, co chceš, nazdar“.
Právě že má. Překladač u volání podle typu ví buďto přesně (jednoduché volání), nebo alespoň omezeně (pokus o polymorfismus ve formě dědičného pseudopolymorfismu), který kód se spustí. U zasílání zprávy to z podstaty nejde, protože tu samou zprávu je možno poslat kterémukoliv objektu, kdy každý může spouštět jinou činnost, a to pokaždé jinou.
„Překladač samozřejmě ani u dědičného polymorfismu neví jaký kód se spustí.“
Proč reagujete, když nedáváte pozor?
Narazí-li překladač na volání metody, která není překrytá (což může být dost často), namastí ji do překladu natvrdo. Je-li překrytá, použije VMT, to jsem ale psal, kdybyste dával pozor, věděl byste to.
„Zasílání zpráv lze pomocí dědičného OOP udělat taky, takže se to v principu neliší. Akorát by to bylo ukecanější...“
Naprogramovat jiný jazyk v tom původním, nebo to mít již jako součást jazyku, to je trochu jiná liga.
> použije VMT, to jsem ale psal
Ne, to jste nepsal. Vy jste psal, že překladač omezeně ví, jaký kód se spustí. Faktem je, že překladač o spouštěném kódu v tu chvíli neví vůbec nic. Ale je možné, že si pod "omezeně ví" představujete něco zcela jiného než já.
> Naprogramovat jiný jazyk
Nemluvím o programování jiného jazyka, ale obecně o implementaci zasílání zpráv pomocí OOP.
> Právě že má. Překladač u volání podle typu ví buďto přesně (jednoduché volání), nebo alespoň omezeně (pokus o polymorfismus ve formě dědičného pseudopolymorfismu)
Nikoliv. Klasické volání virtuální funkce je pro překladač naprosto neprůhledná bariéra. Nemůže předpokládat vůbec nic, protože volaný kód ještě v době překladu nemusí být vůbec napsaný. Např. v C++ překladač nemůže předpokládat ani to, že příští volání té stejné metody zavolá stejný kód a musí tu VFT přečíst při každém volání.
Bohužel tahle flexibilita obvykle přináší víc škody než užitku. Takže se optimalizátory dost intenzivně snaží o spekulativní devirtualizaci. Zdůrazňuji že spekulativní. Překladač může maximálně hádat a musí být připraven na situaci, že se netrefí.
"Rozdíl je v tom, že volání metody je pouze spuštění cílového kódu s příslušnými parametry, které se hodí na zásobník,"
v dynamickych jazycich tomu tak urcite neni. O tom ktery kod se spusti se rozhoduje v case behu, muzete to chovani vetsinou libovolne menit ruznymi hooky. Parametry se nepredavaji na zasobniku, ale v nejakem slovniku/poli.
Nevidim moc velky rozdil oproti Smalltalku, jen s tim Smalltalk mozna prisel prvni, dnes je to temer vsude.
To je dle meho (dalsi) mytus ktery smalltalkari radi rikaji (a kdyz uz ne mytus tak je to alespon dost zavadejici). Ve Smalltalku (resp. Smalltalk-80) se "zprava" jako takova se stava objektem jen a pouze pokud ji neni mozne "dorucit". Do te doby s ni neni mozne jakkoli manipulovat (tedy, ani ji poslat zpravu)
To jo, jenže když je ji “možné doručit,” tak se o tom volání všechno ví (selektor, signatura), takže by ta reifikace byla k ničemu. Ono je hezké mít zprávu jako objekt, jenže to s sebou nese značnou režii. V Objective-C dokonce existuje několik mechanismů doručování zpráv právě kvůli snížení režie. Nejvyšší režie je při posílání zpráv po síti, kde je ovšem i ta nejhorší režie nic v porovnání s latencí přenosu.
> Asi jako mezi voláním funkce a HTTP požadavkem.
Nerekl bych. Je to - dle meho - jen terminologie.
V Pythonu se "vola metoda". V Ruby se "vola metoda". V Jave se "vola metoda", jen smalltalkari trvaji na tom, ze "se smalltalku se nevolaji metody ale posilaji zpravy!".
Prakticky se ve vsech zminenych jazycich, alespon podle toho co vim, deje v zasade to same - lookup v tabulce podle jmena (Java je, pravda, trochu specialni pripad s INVOKESPECIAL, INVOKEVIRTUAL a INVOKEINTERFACE,
nicmene alespon OpenJ9 implementuje a optimalizuje INVOKEINTERFACE stejne jako OSVM implementuje a optimalizuje "poslani zpravy" - a Java na intefacech take "vola metodu").
Suma sumarum, neprijde mi, ze tady se Smalltalk tak zasadne odlisuje, aby to bylo nutne (tak moc) zduraznovat
I smalltalkeři tomu zhusta říkají volání metody, když si zrovna nedávají pozor na jazyk. Ale rozlišovat by se to mělo alespoň v didaktických článcích, protože je velký rozdíl mezi zasíláním zpráv a třeba voláním metody v C++, kdy se může vesele vykonat její kód, i když je příjemce zprávy NULL (a to dokonce někdy bez vyvolání chyby).
Bacha, v C++ volat metodu přes nullpointer nesmíš. Překladač ti to dovolí, ale je to nedefinované chování. Uvnitř metod může překladač předpokládat, že this není nikdy nullpointer a optimalizovat podle toho.
Třeba gcc ten test na nullpointer bez milosti vyoptimalizuje pryč : https://godbolt.org/z/h916G7
V C++ je this pointer a ne reference jen proto, že v začátcích C++ reference vůbec nemělo.
Však se to v různých API jiných jazyků také používá. Promise, Optional, Stream...
Benefitem je, že je sémantika navržená na míru toho API. Je zde tedy lepší čitelnost, idiomatický zápis obvyklých konstruktů a kratší kód. Samozřejmě, při špatném návrhu to může vést k opaku. Navíc to jsou do určité míry subjektivní hlediska, takže hodnocení dvou lidí se bude lišit.
Jo, tohle Smalltalkeři říkají často. Akorát s tím termínem přišla i Simula která vznikla ještě před Smalltalkem. A ty jiné objektové jazyky jako C++ nebo Java vycházejí právě ze Simuly.
Ono se není čemu divit. Slovo objekt se při modelování světa přímo nabízí. A taky je tak zatraceně vágní, že se pod ním může schovávat skoro cokoliv. Sám Kay se později vyjádřil, že to jméno zvolil fakt blbě.
"However, there was a need to obtain access to the
contents of an object from outside the object.
In a model containing "customers" and "clerks"
the active agent would need access to its own
data as well as those of the partner during
service" .
https://hannemyr.com/cache/knojd_acm78.pdf
10. 8. 2020, 18:10 editováno autorem komentáře
Uvedený dokument je sepsán dodatečně (sám to v 2. odstavci zmiňuje) až v roku 1978. Dle Kaye pochází jeho termín z roku 1967. Navíc „object“ a „object oriented“ (OO) asi nebude to samé.
JavaScript nemá nelokální return, takže plnohodnou náhradu řídících struktur takto nevyrobíte Když napíšete `(1 + 1 === 2).ifTrue(() => return "success")`, je to něco jiného než `if (1 + 1 === 2) return "success";`
Díky použití zpráv můžete vytvořit snadno snadno další varianty, které budou se stávajícími konzistentní (ifNil:, ifEmpty:, ifExists:, ifAbsent:, ifError:...) a bude to fungovat třeba i pro proxy objekty.
Ale tak nikdy nebudete schopni vytvořit třeba rozumně vypadající "guard clause".
Zprávy ifNil: a podobné můžete udělat i v jiných jazycích, ale pokud nebudou mít podporu pro nelokální návrat, bude to hodně dřít a stále to nebude konzistentní, protože ty jazyky mají speciální syntaxi pro řídící struktury (čest výjimkám, jako je Lisp a Forth).