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

Radek Miček

Re:Omezená dědičnost (je něco lepšího než OOP?)
« Odpověď #285 kdy: 14. 09. 2015, 00:09:54 »
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 :()?
Třeba u GC se dá využít toho že všechny ukazatele ukazují na starší data.

Pokud máte rekurzi a líné datové struktury, tak to nemusí platit - například v Haskellu to neplatí.


zboj

  • *****
  • 1 507
    • Zobrazit profil
    • E-mail
Re:Omezená dědičnost (je něco lepšího než OOP?)
« Odpověď #286 kdy: 14. 09. 2015, 05:58:25 »
Včera jsem narazil na zatím nejhezčí příklad využití protokolů bez dědičnosti. Potřeboval jsem naimplementovat strukturu rysů s unifikací. Ve strukturách obvykle můžou být atomické hodnoty (zde pouze řetězec) a rekurzivně struktury rysů samy (někdy také množiny a případně další kolekce, ale to by už bylo triviální). Takto to jde nejjednodušeji:

Kód: [Vybrat]
protocol Unifiable : CustomStringConvertible {
    func unifiedWith(value:Unifiable) -> Unifiable?
}

class FeatureStructure : Unifiable {
    var features:[String:Unifiable] = [:]
    subscript(key:String) -> Unifiable? {
        get { return features[key] }
        set(value) { features[key] = value }
    }
    func unifiedWith(value:Unifiable) -> Unifiable? {
        if let value = value as? FeatureStructure {
            // some complicated stuff
        }
        return nil
    }
    var description:String {
        return "[" + ",".join(features.map { (key,value) in "\(key)=\(value)" }) + "]"
    }
}

extension String : Unifiable {
    func unifiedWith(value:Unifiable) -> Unifiable? {
        if let value = value as? String { return value == self ? self : nil }
        return nil
    }
    public var description:String { return self }
}

let fs1 = FeatureStructure()
fs1["a"] = "1"
let fs2 = FeatureStructure()
fs2["b"] = "2"
print("\(fs1) ⨆ \(fs2) = \(fs1.unifiedWith(fs2))")

Elegance sama :)

Inkvizitor

Re:Omezená dědičnost (je něco lepšího než OOP?)
« Odpověď #287 kdy: 14. 09. 2015, 07:59:38 »
Swift neznám, díky tomu snippetu by se ze mě ale konvertita nestal. Musím říci, že já osobně dostávám z myšlenky "nulovatelných typů" kopřivku, ale zajímavé by bylo porovnat "opravdovou" verzi třeba právě s implementací v Haskellu. Protože třeba v Pythonu si to dovedu představit díky ducktypingu za podstatně menších bolestí (jasně, ty třídy by bez dědičnosti nebyly ocejchovány ala Unifiable?, ale ta nulovatelnost podle mě stejně degraduje typový systém, takže to podle mě vyjde skoro nastejno).

noef

  • *****
  • 897
    • Zobrazit profil
    • E-mail
Re:Omezená dědičnost (je něco lepšího než OOP?)
« Odpověď #288 kdy: 14. 09. 2015, 08:22:22 »
Nezapomínej, že to rozdělení musí být logické, ne adminstrativní.
Logicke rozdeleni to je z pohledu vykonu - pri kazde zmene chunku (napr. zniceni bloku) je treba znovu vytvorit mesh (3d "model" chunku, rendrovat blok po bloku to opravdu nejde, vytvori se jen model s viditelnymi stranami bloku), coz je draha operace a pri nevhodne velikosti to povede k vykonostnim problemum (velky chunk -> casteji a dlouho se generuje, maly chunk -> vice rezie).

A klidně to můžeš dělat i během života (postaví zeď atd).
Po pravde, az takto dynamicke rozdelovani sveta zni velmi narocne. Kdyz si vezmu, ze jen hloupy algoritmus pro svetlo (trivialni flood-fill, navic s podstatne nizsim polomerem nez je napr. dostrel luku) pusobi vykonostni problemy.

Kit

Re:Omezená dědičnost (je něco lepšího než OOP?)
« Odpověď #289 kdy: 14. 09. 2015, 08:34:06 »
Musím říci, že já osobně dostávám z myšlenky "nulovatelných typů" kopřivku ...  ale ta nulovatelnost podle mě stejně degraduje typový systém, takže to podle mě vyjde skoro nastejno.

Tak používej nullové singletony, které to elegantně řeší.


Re:Omezená dědičnost (je něco lepšího než OOP?)
« Odpověď #290 kdy: 14. 09. 2015, 08:56:31 »
Řekněme, že chci mít objekty čtverec, obdélník, kosočtverec a rovnoběžník. Je jasné, že s jednoduchou dědičností se daleko nedostanu. Proto obecný dotaz: existuje nějaké ... ?

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

Doufám, že jste tazatelovi pomohli ...

Inkvizitor

Re:Omezená dědičnost (je něco lepšího než OOP?)
« Odpověď #291 kdy: 14. 09. 2015, 09:18:17 »
Musím říci, že já osobně dostávám z myšlenky "nulovatelných typů" kopřivku ...  ale ta nulovatelnost podle mě stejně degraduje typový systém, takže to podle mě vyjde skoro nastejno.

Tak používej nullové singletony, které to elegantně řeší.

Když já bych raději option types a pattern matching. ;-)

nula

Re:Omezená dědičnost (je něco lepšího než OOP?)
« Odpověď #292 kdy: 14. 09. 2015, 09:37:47 »
Ty dvě počítané vlastnosti jsou tam zcela zbytečné. A co je zbytečné, musí pryč.
Ty počítané vlastnosti rozhodně nejsou zbytečné. Slouží k tomu aby šel čtverec použít všude tam, kde se dá použít rovnoběžník. Pokud mám třeba funkci na kreslení rovnoběžníka, tak pokud má čtverec tyhle dvě "zbytečné" vlastnosti tak ho tímhle způsobem můžu nakreslit taky.

Nebo chci přidat funkci pro obvod. Ve tvém případě musím tu funkci dodat do interface a doimplementovat ve všech odvozených třídách. Není jednodušší napsat jedinou funkci, která spočítá obvod rovnoběžníka a v případě čtverce využívá ty "zbytečné" počítané vlastnosti?

Jak uz od zacatku tady nekdo rikal, vsechno zavisi na zpusobu pouziti.
Tyhle zobecnovani, co tady delas zas vedou tomu, ze casto to co kompl zvladl pred 20 lety s tehdejsim hw, dela dneska na 20 let novejsim hw stejnou dobu. Kdyz budes mit miliardy ctvercu a budes je nekde muset skladovat a budes potrebovat pocitat jejich obsahy, tak si sakra rozmyslis, jestli tam budes nekde pocitat cos, drzet si zbytecne data, atp.

Odtud pak vznikaji napriklad tragicke aplikace v Jave - nepouzitelny lagovaci moloch, prestoze Java sama o sobe umi byt i relativne hodne rychla.

JSH

Re:Omezená dědičnost (je něco lepšího než OOP?)
« Odpověď #293 kdy: 14. 09. 2015, 10:02:06 »
Jak uz od zacatku tady nekdo rikal, vsechno zavisi na zpusobu pouziti.
Tyhle zobecnovani, co tady delas zas vedou tomu, ze casto to co kompl zvladl pred 20 lety s tehdejsim hw, dela dneska na 20 let novejsim hw stejnou dobu. Kdyz budes mit miliardy ctvercu a budes je nekde muset skladovat a budes potrebovat pocitat jejich obsahy, tak si sakra rozmyslis, jestli tam budes nekde pocitat cos, drzet si zbytecne data, atp.
Já znám protokoly primárně z Haskellu. Nevím jak jinde ale v Haskellu tu potřebnou tabulku funkcí hlídá a předává překladač. A taky ty funkce ochotně inlinuje všude, kde to jenom jde. Takže pokud budu mít miliardy čtverců a budu si jistý tím že to jsou čtverce, tak mi překladač zainlinuje volání a kosinus vyoptimalizuje pryč.

Zrovna protokoly jsou abstrakce, která umí být překvapivě levná. Teda aspoň v příčetně navrženém jazyce.

Kit

Re:Omezená dědičnost (je něco lepšího než OOP?)
« Odpověď #294 kdy: 14. 09. 2015, 10:54:31 »
Já znám protokoly primárně z Haskellu. Nevím jak jinde ale v Haskellu tu potřebnou tabulku funkcí hlídá a předává překladač. A taky ty funkce ochotně inlinuje všude, kde to jenom jde. Takže pokud budu mít miliardy čtverců a budu si jistý tím že to jsou čtverce, tak mi překladač zainlinuje volání a kosinus vyoptimalizuje pryč.

Zrovna protokoly jsou abstrakce, která umí být překvapivě levná. Teda aspoň v příčetně navrženém jazyce.

Haskell má lenošení v popisu práce - bez něj by byl nepoužitelný. Objektové jazyky na tom bývají hůř, protože když to nezvládnou zoptimalizovat při překladu, tak za běhu to už nedohoní a ten kosinus budou počítat vždy.

Překladače pro OO jazyky umí obvykle velmi dobře optimalizovat uvnitř jedné třídy. Prakticky všechny vnitřní metody inlinují, takže je úplně jedno, jestli mám jednu velkou metodu nebo 20 drobných, které se volají mezi sebou. Všechny privátní gettery a settery konvertují na přímé přístupy k atributům.

Vně třídy však už tolik možností nemají - proto public gettery/settery a public atributy nepoužívám. Jsou moc drahé. Místo toho dávám kód, který s těmi atributy potřebuje pracovat, přímo dovnitř třídy a tím optimalizaci umožním.

gamer

Re:Omezená dědičnost (je něco lepšího než OOP?)
« Odpověď #295 kdy: 14. 09. 2015, 11:25:40 »
A to ti nevadi, ze vysledek vypoctu zalezi na tom, co jsi oznacil za panaka 1 a za panaka 2?

To mi vůbec nevadí, pro mě je důležité mít svět v konzistentním stavu, což je vždy zaručeno.

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

S tím naprosto souhlasím.

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.

Já ty jiné způsoby vidím a vidím je i bez FP, problém je jinde. Řeším svět tak složitý, že ho nedokážu rozumně rozdělit na nezávislé části. Proto volím imperativní přístup s mutable světem a postupným výpočtem. Tím ten problém zredukuju na výpočet interakce jednoho objektu s okolním (v tu chvíli konstantním) světem. Pokud provedu nezávislé výpočty a snažím se je dát dohromady, je to problém řádově složitější, každý objekt je v interakci s každým.

Zatím všechny velké hry, které jsem viděl, to dělají právě takto, např. v Unreal Engine: https://udn.epicgames.com/Three/ActorTicking.html
Prakticky nic paralelního tam není. Některé entity se dají pustit paralelně se simulací fyziky, ale to je dost slabá optimalizace, hodí se to jen pro jednoduché entity bez fyziky. Oni by to taky rádi udělali paralelně, protože update entit v game threadu bývá dost často slabým místem z hlediska výkonu, ale prostě to neumí líp. A nemyslím si, že FP jim s tím pomůže.

A z toho co rikas mi tak trochu pripada, ze to vlastne delat nechces, kdyz rikas, ze by to "bylo slozite".

Ano nechci, z mého pohledu je to složité.

zboj

  • *****
  • 1 507
    • Zobrazit profil
    • E-mail
Re:Omezená dědičnost (je něco lepšího než OOP?)
« Odpověď #296 kdy: 14. 09. 2015, 11:47:01 »
Swift neznám, díky tomu snippetu by se ze mě ale konvertita nestal. Musím říci, že já osobně dostávám z myšlenky "nulovatelných typů" kopřivku, ale zajímavé by bylo porovnat "opravdovou" verzi třeba právě s implementací v Haskellu. Protože třeba v Pythonu si to dovedu představit díky ducktypingu za podstatně menších bolestí (jasně, ty třídy by bez dědičnosti nebyly ocejchovány ala Unifiable?, ale ta nulovatelnost podle mě stejně degraduje typový systém, takže to podle mě vyjde skoro nastejno).

V dynamickém jazyku to takto půjde vždy (Python, ObjC), zde je výhoda právě ve statickém typování.

zboj

  • *****
  • 1 507
    • Zobrazit profil
    • E-mail
Re:Omezená dědičnost (je něco lepšího než OOP?)
« Odpověď #297 kdy: 14. 09. 2015, 11:54:45 »
Ty dvě počítané vlastnosti jsou tam zcela zbytečné. A co je zbytečné, musí pryč.
Ty počítané vlastnosti rozhodně nejsou zbytečné. Slouží k tomu aby šel čtverec použít všude tam, kde se dá použít rovnoběžník. Pokud mám třeba funkci na kreslení rovnoběžníka, tak pokud má čtverec tyhle dvě "zbytečné" vlastnosti tak ho tímhle způsobem můžu nakreslit taky.

Nebo chci přidat funkci pro obvod. Ve tvém případě musím tu funkci dodat do interface a doimplementovat ve všech odvozených třídách. Není jednodušší napsat jedinou funkci, která spočítá obvod rovnoběžníka a v případě čtverce využívá ty "zbytečné" počítané vlastnosti?

Jak uz od zacatku tady nekdo rikal, vsechno zavisi na zpusobu pouziti.
Tyhle zobecnovani, co tady delas zas vedou tomu, ze casto to co kompl zvladl pred 20 lety s tehdejsim hw, dela dneska na 20 let novejsim hw stejnou dobu. Kdyz budes mit miliardy ctvercu a budes je nekde muset skladovat a budes potrebovat pocitat jejich obsahy, tak si sakra rozmyslis, jestli tam budes nekde pocitat cos, drzet si zbytecne data, atp.

Odtud pak vznikaji napriklad tragicke aplikace v Jave - nepouzitelny lagovaci moloch, prestoze Java sama o sobe umi byt i relativne hodne rychla.

Vtip je právě v tom, že data se nikde zbytečně nedrží, už se to tady vysvětlovalo asi třikrát. Pokud je navíc struct pro čtverec neměnná, překladač z přístupu k side2 udělá přímý přístup k side1 a skew bude prostě konstanta. Díky této fázi optimalizací lze pak vyhodit i cos z funkce pro výpočet pro obsah (z metody area bude něco jako area<T> s různou implementací pro různé typy). Takže "miliardy čtverců" v něčem jako Array<Square> by rychleji implementovat ani nešla. Stačí si ten kód pustit s profilerem, pole miliardy čtverců zabere třetinu paměti oproti miliardě rovnoběžníků, pričemž výpočet obsahu je stejně rychlý (s -Ofast pochopitelně).

zboj

  • *****
  • 1 507
    • Zobrazit profil
    • E-mail
Re:Omezená dědičnost (je něco lepšího než OOP?)
« Odpověď #298 kdy: 14. 09. 2015, 12:02:46 »
Řekněme, že chci mít objekty čtverec, obdélník, kosočtverec a rovnoběžník. Je jasné, že s jednoduchou dědičností se daleko nedostanu. Proto obecný dotaz: existuje nějaké ... ?

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

Doufám, že jste tazatelovi pomohli ...
Vzhledem k obecnosti otázky celkem jo, až na to zaplevelení diskusí o FP ve hrách.

JSH

Re:Omezená dědičnost (je něco lepšího než OOP?)
« Odpověď #299 kdy: 14. 09. 2015, 12:14:43 »
Haskell má lenošení v popisu práce - bez něj by byl nepoužitelný. Objektové jazyky na tom bývají hůř, protože když to nezvládnou zoptimalizovat při překladu, tak za běhu to už nedohoní a ten kosinus budou počítat vždy.
Tady ale lazy vyhodnocení ničemu nepomůže. Já mluvil o optimalizacích při kompilaci. Lazy vyhodnocení dělá něco trochu jiného.

Trochu podobnou optimalizaci dělají i OO jazyky. C++ umí taky "odvirtualizovat" volání funkce, pokud si je jisté typem.