Omezená dědičnost (je něco lepšího než OOP?)

JS

Re:Omezená dědičnost (je něco lepšího než OOP?)
« Odpověď #270 kdy: 13. 09. 2015, 12:34:06 »
Možností je spousta, ale mně všechny připadají horší, než imperativní přístup s mutable objekty. Klidně si mysli, že jsem FP nepochopil. Já ti to vyvracet nebudu. Budeme oba spokojeni a můžeme tuto nesmyslnou debatu ukončit.

Ja myslim, ze v jistem smyslu je FP vzdycky "horsi", protoze v jistem smyslu omezuje tvoji svobodu. Asi jako je treba strukturovane nebo modularni programovani horsi nez spagety s globalnim stavem (videl jsem extremne efektivni, ale take extremne neprehledne, programy napsane tim druhym zpusobem). Na co se sazi je, ze urcita konstantni neefektivita (treba to, ze budes kopirovat zmeneny objekt a ne ho menit na miste) je nakonec mensi nevyhodou nez celkova neprehlednost programu. A taky se sazi na to, ze s tim prvnim se kompilatory eventualne vyporadaji (coz u FP zatim tak docela neplati, ale u normalnich kompilatoru take trvalo, nez se naucily vyrobit ze strukturovanych a modularnich programu opet ty velmi efektivni spagety - napriklad inlinovanim funkci).

 Vezmeme si treba to FRP - functional reactive programming - paradigma. Tam se explicitne konstruuje graf udalosti, ktere se zpracovavaji. Na nizsi urovni jsou to treba vstupy z klavesnice, na vyssi pak jednotlive zmenene objekty az na te nejvyssi cela zmenena scena. To je prehlednejsi (aspon co tvrdi zastanci tohoto pristupu) nez mutable objekty proto, protoze explicitne vidis, odkud jaka zmena vychazi; pokud ale muzes kdekoli v programu menit stav nejakeho objektu, tahle informace je v nem pouze implicitni (musis precist cely program, abys ji dohledal). Od kompilatoru se pak ocekava, ze nebude ve skutecnosti posilat udalosti, ale ze ten cely graf nejak "pochopi" a udela z nej ten puvodni system, kde se vsechno jen mutuje ve spravnem poradi (coz je zatim hudba budoucnosti, proto to asi AAA studia nepouzivaji).

Takze IMHO, pokud nevidis prinos v te prehlednosti, kterou potencialne FP muze prinest, treba explicitni zapis toho grafu zavislosti, pak to rozhodne nema smysl pouzit jako metodologii. Nicmene vyvoj programovani se nepochybne ubira timhle smerem - od efektivnich, ale neprehlednych, zapisu k zapisum prehlednejsim (a abstraktnejsim), kde tu efektivitu nejak (snad) obstara kompilator.

(Kdyz jsme tak u toho, FP se casto "prodava" s tim, ze umoznuje vice paralelismu. To je IMHO az druhorady efekt, podobne jako strukturovane programovani muze pomoci snazsimu zapisu algoritmu a tudiz umoznuje pouzit/vyzkouset lepsi/jine algoritmy. Primarni vyhoda FP je IMHO zlepseni prehlednosti operaci s daty.)


Re:Omezená dědičnost (je něco lepšího než OOP?)
« Odpověď #271 kdy: 13. 09. 2015, 13:10:57 »
(Kdyz jsme tak u toho, FP se casto "prodava" s tim, ze umoznuje vice paralelismu. To je IMHO az druhorady efekt, podobne jako strukturovane programovani muze pomoci snazsimu zapisu algoritmu a tudiz umoznuje pouzit/vyzkouset lepsi/jine algoritmy. Primarni vyhoda FP je IMHO zlepseni prehlednosti operaci s daty.)
Presne tak - prvorada vyhoda FP je, ze je tam explicitni a prehledne data flow - pokud data nekam neposles, tak je tam proste nemas k dispozici. Z toho pak plynou ruzne veci, jako napr. ze muzes rychle a presne rozhodnout, v jake casti kodu se jaka data meni a jaka zarucene nemeni, jaky kod je zavisly na jakych datech atd. Moznost paralelizace je pak dusledek tohodle.

gamer

Re:Omezená dědičnost (je něco lepšího než OOP?)
« Odpověď #272 kdy: 13. 09. 2015, 20:01:46 »
Ja myslim, ze v jistem smyslu je FP vzdycky "horsi", protoze v jistem smyslu omezuje tvoji svobodu.

Nejde o to, že FP omezuje svobodu, to je v pohodě, pokud omezení něco přinese. Problém je ale v tomto konkrétním případě mnohem hlubší, FP vede k horšímu technickému řešení.

Řeším složitý dynamický svět s velkým množstvím objektů, které vzájemně interagují. Z definice je to jeden svět, který se mění.
Klasický imperativní přístup respektuje tuto definici, když chci spočítat nový stav, tak postupně iteruji přes všechny objekty, spočítám jim nový stav a taky jim ho hned nastavím. Mezi objekty jsou vzájemné závislosti, když spočítám, že panák 1 vleze na políčko A, tak ho tam rovnou umístím. Panák 2, kterého počítám vzápětí, zná aktuální polohu panáka 1 a ví, že na políčko A nemůže, vybere si třeba B. Takový přímočarý přístup má jednu obrovskou výhodu, na konci výpočtu mám vždy celý svět v konzistentním stavu, nikdy se nemůže stát, že jsou dva panáci na políčku A.

Teď na to chci napasovat funkcionální přístup, chci mít konstatní svět a výpočet bez side effectů. Ono to jde, ale musím si uvědomit, co mi to přinese a co mi to vezme. V zásadě to můžu udělat dvěma způsoby.

První je analogií imperativního přístupu, pokaždé když nastavím nový stav objektu, tak vyrobím celý nový "správný" svět. To bude fungovat naprosto stejně jako imperativní přístup. Má to ale svoje ale. I kdyby výroba nového světa nestála žádný výkon navíc (čemuž nevěřím), tak je takový design silně diskutabilní. Mám prakticky netestovatelné funkce, když funkce vrací celý svět, může potenciálně změnit cokoliv. Vůbec nemám přehled o datech, která do funkcí vstupují a které funkce vrací, z interface to není vidět.

Druhý způsob je nedělat změny ve světě ihned, ale schovat si je na později. Vytvořím seznam událostí, co se má se světem stát. Problém tohoto přístupu je v tom, že dává chybné výsledky a nekonzistentní svět. Když počítám všechno z původního světa, můžou se rozhodnout panácí 1 i 2, že oba vstoupí na pole A. Teď co s tím? Nechám panáka 2 tam, kde je, nebo spustím ex-post znovu AI a najdu pro panáka 2 novou pozici? Obě řešení jsou špatná. Hráč očekává, že panák 2 něco udělá a ne že bude občas "zasekávat". Spouštět znovu AI je nekoncepční a stojí to výkon. I když jde o naprosto elemetární příklad, tak stejně nevím, co s tou kolizí udělat. V reálně hře budou tisíce různých událostí a miliony jejich možných vzájemných kombinací. Já nemám dost dobrý mozek na to, abych dokázal domyslet, jak řešit všechny možné kolize. Nevybral bych si toto řešení ani náhodou. Z mého pohledu je nedeterministické.

Pak jsou samozřejmně možné kombinace obou řešení, spočítám události jen pro některé objekty a až potom vytvořím nový svět, nebo můžu svět držet někde bokem a události do něj posílat asynchronně... fantazii se meze nekladou. Ale bohužel to vždycky vede buď na vytváření nového světa nebo k sekvečnímu zpracování událostí.

Nechtěl bych, aby to vyznělo tak, že imperativní přístup je jediný správný a žádné problémy nemá. Samozřejmně že má. Ale pro mě přináší oproti FP dvě zásadní věci, umožňuje mi udržet rozhraní minimalistické (nemusím všude pracovat s celým světem) a umožňuje mi udržet svět v konzistentním stavu.

noef

  • *****
  • 897
    • Zobrazit profil
    • E-mail
Re:Omezená dědičnost (je něco lepšího než OOP?)
« Odpověď #273 kdy: 13. 09. 2015, 20:13:18 »
Tato diskuze je velmi zajimava :).

... Ale pro mě přináší oproti FP dvě zásadní věci, umožňuje mi udržet rozhraní minimalistické (nemusím všude pracovat s celým světem) a umožňuje mi udržet svět v konzistentním stavu.

V programovani her mam zkusenosti jen s tvorbou modu pro Minecraft, je mozne, ze to jde delat i jinak (nebylo by to poprve). Ale to s minimalistickym rozhranim (minimalne v MC) proste neplati. Napr. z kazde entity mohu vytahnout instnaci sveta a delat uplne cokoliv. To je jen iluze minimalniho rozhrani, pokud stejne mohu pristupovat kamkoliv - je to stejne jako f(world) -> world ve FP. Akorat tam je to explicitne receno, ze se s tim svetem neco muze stat, zatimco pri player.setDirection(1,0,0) nepoznam, jestli to nahodou nezasahuje i do jinych casti sveta. Nebo se v "opravdovych" hrach toto takto neresi (zadne zpetne reference atp.)?

gamer

Re:Omezená dědičnost (je něco lepšího než OOP?)
« Odpověď #274 kdy: 13. 09. 2015, 20:33:27 »
V programovani her mam zkusenosti jen s tvorbou modu pro Minecraft, je mozne, ze to jde delat i jinak (nebylo by to poprve). Ale to s minimalistickym rozhranim (minimalne v MC) proste neplati. Napr. z kazde entity mohu vytahnout instnaci sveta a delat uplne cokoliv. To je jen iluze minimalniho rozhrani, pokud stejne mohu pristupovat kamkoliv - je to stejne jako f(world) -> world ve FP. Akorat tam je to explicitne receno, ze se s tim svetem neco muze stat, zatimco pri player.setDirection(1,0,0) nepoznam, jestli to nahodou nezasahuje i do jinych casti sveta. Nebo se v "opravdovych" hrach toto takto neresi (zadne zpetne reference atp.)?

Ano, většinou to bohužel jde, ale to neznamená, že by se to tak mělo dělat. Vytáhnout instanci světa z entity a pak měnit svět ve funkci, která dostává jako parametr entitu, je ovšem nutné považovat za prasárnu. Nic není ideální, i takové prasárny se bohužel dělají.


Re:Omezená dědičnost (je něco lepšího než OOP?)
« Odpověď #275 kdy: 13. 09. 2015, 21:01:36 »
Takže tu opět máme nebetyčný rozdíl: zatímco v FP se svět přenáší do funkce jako svět, na jednom jasně definovaném místě, což je strašně neelegantní, v ne-FP se přenáší svět do funkce všude možně ve všech možných properties všech možných objektů. Čili to druhé je minimalistické rozhraní a to první je tragédie, kvůli které se hry v FP psát nedají.

A abysme nezapomněli, ten svět se musí při každém volání funkce kopírovat!

:)))))

BoneFlute

  • *****
  • 2 046
    • Zobrazit profil
Re:Omezená dědičnost (je něco lepšího než OOP?)
« Odpověď #276 kdy: 13. 09. 2015, 21:59:54 »
Zajímalo by mě, na jaké nevýhody můžu u FP narazit. Zatím, co vím, tak že takovej Haskell je výkonově na úrovni Javy.  Což zase není tak hrozné, a možná by to chtělo nějaké lepší benchmarky. Napadá vás něco dalšího? Možná sem jen příliš velkej fanda, ale když bych se měl rozmýšlet, zda C++ nebo Haskell, tak neváhám ani okamžik (a to jsem si s C++ pár věcí napsal).

BoneFlute

  • *****
  • 2 046
    • Zobrazit profil
Re:Omezená dědičnost (je něco lepšího než OOP?)
« Odpověď #277 kdy: 13. 09. 2015, 22:10:18 »
Tato diskuze je velmi zajimava :).

... Ale pro mě přináší oproti FP dvě zásadní věci, umožňuje mi udržet rozhraní minimalistické (nemusím všude pracovat s celým světem) a umožňuje mi udržet svět v konzistentním stavu.

V programovani her mam zkusenosti jen s tvorbou modu pro Minecraft, je mozne, ze to jde delat i jinak (nebylo by to poprve). Ale to s minimalistickym rozhranim (minimalne v MC) proste neplati. Napr. z kazde entity mohu vytahnout instnaci sveta a delat uplne cokoliv. To je jen iluze minimalniho rozhrani, pokud stejne mohu pristupovat kamkoliv - je to stejne jako f(world) -> world ve FP. Akorat tam je to explicitne receno, ze se s tim svetem neco muze stat, zatimco pri player.setDirection(1,0,0) nepoznam, jestli to nahodou nezasahuje i do jinych casti sveta. Nebo se v "opravdovych" hrach toto takto neresi (zadne zpetne reference atp.)?

Já jsem tomu objektu nepředával celý svět, ale jen adekvátní výřez (zjednodušení, ve skutečnosti jsem to měl optimalizované ještě jinak). Například když byl objekt jakože v místnosti, tak dostal jen tu místnost. Protože za zeď nevidí, že jo. Mělo to ten efekt, že jsem to mohl paralelizovat, každá "místnost" mohla běžet samostatně. Myslím, že Prýmek tomu říkal partioning.

Re:Omezená dědičnost (je něco lepšího než OOP?)
« Odpověď #278 kdy: 13. 09. 2015, 22:19:00 »
Já jsem tomu objektu nepředával celý svět, ale jen adekvátní výřez (zjednodušení, ve skutečnosti jsem to měl optimalizované ještě jinak).
Jo, to je právě na FP hezký - protože máš stav explicitní, na jednom místě, víš dobře, co souvisí s čím, co k výpočtu potřebuješ a co nepotřebuješ. Takže můžeš krásně udělat řez na pravém místě a ty dvě (popř. víc) částí zpracovávat zvlášť. U OOP máš síť, kde je obvykle všechno spojený se vším a řez neuděláš. Čili ani nic neparalelizuješ. Leda triviálně - zkusíš to pustit ve víc vlákneš a zamykáš, zamykáš, zamykáš, čili jestli se to zrychlí nebo nezrychlí nemáš nikdy šanci odhadnout, protože nevíš, kolikrát se ty zámky potkají...

Vlastně docela podobným způsobem zjistíš i které části dat už nikdy nebudeš potřebovat a s klidem je zahodíš. Má to hodně zajímavé efekty: https://plus.google.com/+MiroslavPrymek/posts/VyNUxy5pqei

BoneFlute

  • *****
  • 2 046
    • Zobrazit profil
Re:Omezená dědičnost (je něco lepšího než OOP?)
« Odpověď #279 kdy: 13. 09. 2015, 22:23:04 »
No, o výhodách mi vyprávět nemusíš ;-) Mě by spíše zajímaly nějaké problémy, nevýhody, co se v FP řeší výrazně hůř, než v mutable světě.

noef

  • *****
  • 897
    • Zobrazit profil
    • E-mail
Re:Omezená dědičnost (je něco lepšího než OOP?)
« Odpověď #280 kdy: 13. 09. 2015, 22:28:41 »
Já jsem tomu objektu nepředával celý svět, ale jen adekvátní výřez (zjednodušení, ve skutečnosti jsem to měl optimalizované ještě jinak). Například když byl objekt jakože v místnosti, tak dostal jen tu místnost. Protože za zeď nevidí, že jo. Mělo to ten efekt, že jsem to mohl paralelizovat, každá "místnost" mohla běžet samostatně. Myslím, že Prýmek tomu říkal partioning.
To zni zajimave, bohuzel si nejsem jisty, jestli to muze vsude fungovat - napr. ten zminovany Minecraft. Kdyz mam svet rozdeleny na casti (chunky - 16x16x256 bloku IIRC), tak hrac na kraji jednoho chunku zcela jiste muze (a casto bude) interagovat z blokem z jineho chunku. Mozna to rozsekat podle maximalniho mozneho dosahu jakekoliv interakce s prostredim, nebo podle dohlednosti? Co jsem kod videl posledne, tak se to proste neresilo - pro kazdy svet bylo vse serializovane (ticky bloku, entit, tile entit).

Zajímalo by mě, na jaké nevýhody můžu u FP narazit. Zatím, co vím, tak že takovej Haskell je výkonově na úrovni Javy.  Což zase není tak hrozné, a možná by to chtělo nějaké lepší benchmarky. ...
To me celkem zarazilo, myslel jsem, ze Oracli HotSpot ma celkem vychytany optimalizace za behu. Nebo ze by ten funkc. pristup byl o tolik lepe optimalizovatelny (ve Scale jsem pozoroval spise opak :()?

zboj

  • *****
  • 1 507
    • Zobrazit profil
    • E-mail
Re:Omezená dědičnost (je něco lepšího než OOP?)
« Odpověď #281 kdy: 13. 09. 2015, 22:31:26 »
Zajímalo by mě, na jaké nevýhody můžu u FP narazit. Zatím, co vím, tak že takovej Haskell je výkonově na úrovni Javy.  Což zase není tak hrozné, a možná by to chtělo nějaké lepší benchmarky. Napadá vás něco dalšího? Možná sem jen příliš velkej fanda, ale když bych se měl rozmýšlet, zda C++ nebo Haskell, tak neváhám ani okamžik (a to jsem si s C++ pár věcí napsal).

http://www.rarous.net/weblog/448-deset-duvodu-proc-nepouzivat-funkcionalni-jazyky.aspx :)

JS

Re:Omezená dědičnost (je něco lepšího než OOP?)
« Odpověď #282 kdy: 13. 09. 2015, 22:51:58 »
Nejde o to, že FP omezuje svobodu, to je v pohodě, pokud omezení něco přinese. Problém je ale v tomto konkrétním případě mnohem hlubší, FP vede k horšímu technickému řešení.

To jsem ti prece psal. Je to uplne analogicka situace te pred 50 lety, kdyz pouzivani mnoha malych funkci take vedlo k horsimu technickemu reseni, protoze kompilatory neumely inlining. Takze pokud mas za to, ze se ti to neoplati, nepouzivej to.

Musis si uvedomit, ze to "kopirovani" stavu sveta je jen formalismus. Dostatecne chytry kompilator to delat nemusi, pokud prijde na to, ze ten predchozi stav uz nikde nepotrebujes.

Citace
Řeším složitý dynamický svět s velkým množstvím objektů, které vzájemně interagují. Z definice je to jeden svět, který se mění.
Klasický imperativní přístup respektuje tuto definici, když chci spočítat nový stav, tak postupně iteruji přes všechny objekty, spočítám jim nový stav a taky jim ho hned nastavím. Mezi objekty jsou vzájemné závislosti, když spočítám, že panák 1 vleze na políčko A, tak ho tam rovnou umístím. Panák 2, kterého počítám vzápětí, zná aktuální polohu panáka 1 a ví, že na políčko A nemůže, vybere si třeba B. Takový přímočarý přístup má jednu obrovskou výhodu, na konci výpočtu mám vždy celý svět v konzistentním stavu, nikdy se nemůže stát, že jsou dva panáci na políčku A.

A to ti nevadi, ze vysledek vypoctu zalezi na tom, co jsi oznacil za panaka 1 a za panaka 2?

Nicmene, oba dva pristupy, ktere popisujes, a mnohe dalsi, lze realizovat funkcionalne. V podstate lze celou tu zalezitost abstrahovat do vhodne monady (tyto mohou - mimo jine - predstavovat zpusoby, jak skladat vypocty). Ten prvni zpusob odpovida klasicke stavove monade, kdy se za stav bere samotny stav sveta. Druhy zpusob - nenapsal jsi ovsem co by to melo byt; dejme tomu, ze se v tom pripade ta kolize nejak dodatecne vyresi (treba zvitezi silnejsi postava) - lze take schovat do vhodne monady. Muzeme mit napriklad i treti zpusob, ktery v pripade kolize vrati obe postavy v puvodnim stavu; tomu by zase odpovidala jina monada.

Ve funkcionalnim pristupu si muzes explicitne vybrat, jakym zpusobem ty stavy sveta (nebo i jenom podstavy) skladat (prostrednictvim jake monady). To je cele, je to jen formalismus, jestli se skutecne pak bude v tom programu neco kopirovat nebo se bude neco vyhodnocovat pozdeji je jina otazka (z hlediska efektivity nicmene podstatna), totiz otazka co s tim svede kompilator.

Citace
Nechtěl bych, aby to vyznělo tak, že imperativní přístup je jediný správný a žádné problémy nemá. Samozřejmně že má. Ale pro mě přináší oproti FP dvě zásadní věci, umožňuje mi udržet rozhraní minimalistické (nemusím všude pracovat s celým světem) a umožňuje mi udržet svět v konzistentním stavu.

Jak uz bylo receno, pokud muzes kdekoli ten svet zmenit, tak s nim fakticky vsude pracujes, akorat to explicitne nerikas. Uplny analog tomu je pouzivat vsude stavovou monadu se stavem celeho sveta pro skladani tech zmen stavu. Pak samozrejme pouzitim FP nic neziskas (je to podobne asi jako pouzivat staticky typovy system jen s jednim univerzalnim typem, ktery odpovida hodnote v dynamicky typovanem jazyce). Vyhodu ti to prinese az v momente, kdy nahlednes, ze existuji i jine zpusoby, jak skladat stavy jednotlivych prvku sveta, nez mutovat cely svet; pak je muzes vhodne funkcionalne abstrahovat.

A z toho co rikas mi tak trochu pripada, ze to vlastne delat nechces, kdyz rikas, ze by to "bylo slozite". Obavam se ale, ze tim, ze tohle nechces resit, sis ten problem zjednodusil az prilis a riskujes vic chyb (prikladem muze byt treba ta zahada, ze panak 1 ma vzdycky prednost pred panakem 2). Ono nakonec proti gustu - ja treba nemam rad staticke typovani, prestoze si uvedomuji, ze definovat si treba vysku a vahu jako ruzne typy muze vest k vetsi korektnosti programu. Je proste dobre si uvedomit, o co se tou volbou pripravujes.

BoneFlute

  • *****
  • 2 046
    • Zobrazit profil
Re:Omezená dědičnost (je něco lepšího než OOP?)
« Odpověď #283 kdy: 13. 09. 2015, 23:07:34 »
To zni zajimave, bohuzel si nejsem jisty, jestli to muze vsude fungovat - napr. ten zminovany Minecraft. Kdyz mam svet rozdeleny na casti (chunky - 16x16x256 bloku IIRC), tak hrac na kraji jednoho chunku zcela jiste muze (a casto bude) interagovat z blokem z jineho chunku. Mozna to rozsekat podle maximalniho mozneho dosahu jakekoliv interakce s prostredim, nebo podle dohlednosti? Co jsem kod videl posledne, tak se to proste neresilo - pro kazdy svet bylo vse serializovane (ticky bloku, entit, tile entit).
Nezapomínej, že to rozdělení musí být logické, ne adminstrativní. A za druhé, rozdělovat to můžeš a nemusíš. A klidně to můžeš dělat i během života (postaví zeď atd).

JSH

Re:Omezená dědičnost (je něco lepšího než OOP?)
« Odpověď #284 kdy: 13. 09. 2015, 23:21:10 »
To me celkem zarazilo, myslel jsem, ze Oracli HotSpot ma celkem vychytany optimalizace za behu. Nebo ze by ten funkc. pristup byl o tolik lepe optimalizovatelny (ve Scale jsem pozoroval spise opak :()?
Je tam pár věci, které dost zajímavě pomáhají. Třeba u GC se dá využít toho že všechny ukazatele ukazují na starší data. A high level optimalizace v Haskellu jsou něco, na co jsem ze začátku koukal jako z jara. V komentářích se dá optimalizátoru i poradit, jak má kód upravovat. Třeba z nějakého nagenerování a součtu seznamu dokáže ten seznam komplet vyhodit a převést to na cyklus.
U Scaly bych to možná svedl i na to, že na rozdíl od Haskellu nepoužívá specializovaný runtime.