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.