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

Re:Omezená dědičnost (je něco lepšího než OOP?)
« Odpověď #150 kdy: 11. 09. 2015, 15:18:45 »
s immutable objekty
Pardon, tady jsem myslel spíš "data" než "objekty" ve smyslu OOP.


Kit

Re:Omezená dědičnost (je něco lepšího než OOP?)
« Odpověď #151 kdy: 11. 09. 2015, 15:19:14 »
Zdá se mi to, nebo ten příklad je ve skutečnosti zbytečně komplikovaný a má daleko k eleganci?

Kde se dá zjednodušit?

Tento jazyk neznám, ale vidím tam funkci s nesmyslným názvem area(), která je vložena do nějakého rodiče obou objektů. Něco podobného dělají v PHP traits. Ovšem už ze zápisu té funkce vidím, že u čtverce zbytečně počítá cos(skew) - je vždy roven jedné. Raději napíši do každé třídy jiný vzoreček pro výpočet obsahu, než abych do třídy Čtverec dával atribut skew, který tam sémanticky vůbec nepatří. Místo jednoho atributu tam máš tři atributy - z toho dva jsou zcela zbytečné. Čtverec má jen jeden atribut a tím je délka strany.

Kód: [Vybrat]
interface Areable  {
    Double area()
}

struct Parallelograma : Areable {
    var side1: Double
    var side2: Double
    var skew: Double

    init(side1 s1: Double, side2 s2: Double, skew s: Double) {
        side1 = s1
        side2 = s2
        skew = s
    }

    func area() -> Double {
        return side1 * side2 * cos(skew)
    }
}

struct Square : Areable {
    var side: Double

    init(side s1: Double) {
        side = s1
    }

    func area() -> Double {
        return side * side
    }
}

let figure1 = Parallelogram(side1: 2, side2: 3, skew: M_PI_4)
let figure2 = Square(side: 3)
var list:Array<Areable> = [ figure1, figure2 ]
print(list.map { $0.area() })

Jak vidíš, zápis je ještě kratší, ještě jednodušší a pro mnohé i čitelnější.

JSH

Re:Omezená dědičnost (je něco lepšího než OOP?)
« Odpověď #152 kdy: 11. 09. 2015, 15:23:12 »
Záleží na aplikaci, když to bude geometrický tvar v počítačové hře, tak s immutable moc nepochodíš, tvar a poloha objektů se mění neustále.
Tohle je zajímavá otázka. Je lepší mít mutable scénu, upravovat ji a řešit synchronizaci? Nebo je lepší immutable scéna, update vytvoří novou, jen zrecykluje všechno co se nezměnilo?
Já vidím to immutable řešení jako podstatně elegantnější a i celkem efektivní. A není to jen moje teoretizování. Nenašel jsem přednášku kohosi od Epicu, kde jsem to slyšel poprvé, ale něco podobného zaznělo i tu https://www.youtube.com/watch?v=1PhArSujR_A.

zboj

  • *****
  • 1 507
    • Zobrazit profil
    • E-mail
Re:Omezená dědičnost (je něco lepšího než OOP?)
« Odpověď #153 kdy: 11. 09. 2015, 15:29:02 »
Tohle je IMO chyba. Schválně se při programování občas zastav a zamysli se kolik objektů upravuješ a kolik jich vytvoříš a pak jenom předáš. U mně ty immutable objekty jednoznačně vedou a to píšu hlavně v C++, které na to nějak extra zatížené není.

Immutable objekty řeší daleko víc věcí než jenom tohle. Zásadně mění třeba způsob jak synchronizovat vlákna.

Většinu objektů píšu hlavně proto že potřebuji mutable data a udržet data při změnách konzistentní, nepřekvapivě. Kdyby věděl, že čtvercoobdélníky budou immutable, je pravděpodobné že bych objekty vůbec nepoužil. Synchronizaci vláken mám vyřešenou k dokonalosti.

1) Nejde (kromě C++, to je na jinou debatu).
2) Právě neměnnost objektů je velká výhoda, i když v tomto případě jde spíše o to, jak se používají protokoly.

Protokoly nejdou. Napsat čtyři potomky, to vše bez setterů, jde skoro všude.
Výhoda neměnnosti objektů je vykoupena nevýhodou jejich neustálého kopírování a měnění pointerů na novou kopii a to přináší zase jiné problémy.
Pointerů? U struct?

zboj

  • *****
  • 1 507
    • Zobrazit profil
    • E-mail
Re:Omezená dědičnost (je něco lepšího než OOP?)
« Odpověď #154 kdy: 11. 09. 2015, 15:35:06 »
Zdá se mi to, nebo ten příklad je ve skutečnosti zbytečně komplikovaný a má daleko k eleganci?

Kde se dá zjednodušit?

Tento jazyk neznám, ale vidím tam funkci s nesmyslným názvem area(), která je vložena do nějakého rodiče obou objektů. Něco podobného dělají v PHP traits. Ovšem už ze zápisu té funkce vidím, že u čtverce zbytečně počítá cos(skew) - je vždy roven jedné. Raději napíši do každé třídy jiný vzoreček pro výpočet obsahu, než abych do třídy Čtverec dával atribut skew, který tam sémanticky vůbec nepatří. Místo jednoho atributu tam máš tři atributy - z toho dva jsou zcela zbytečné. Čtverec má jen jeden atribut a tím je délka strany.

Kód: [Vybrat]
interface Areable  {
    Double area()
}

struct Parallelograma : Areable {
    var side1: Double
    var side2: Double
    var skew: Double

    init(side1 s1: Double, side2 s2: Double, skew s: Double) {
        side1 = s1
        side2 = s2
        skew = s
    }

    func area() -> Double {
        return side1 * side2 * cos(skew)
    }
}

struct Square : Areable {
    var side: Double

    init(side s1: Double) {
        side = s1
    }

    func area() -> Double {
        return side * side
    }
}

let figure1 = Parallelogram(side1: 2, side2: 3, skew: M_PI_4)
let figure2 = Square(side: 3)
var list:Array<Areable> = [ figure1, figure2 ]
print(list.map { $0.area() })

Jak vidíš, zápis je ještě kratší, ještě jednodušší a pro mnohé i čitelnější.

1) Co je na area nesmyslného? Možná se douč AJ.
2) Omyl, u čtverce je jen jeden atribut, zbytek jsou computed properties. To nejsou atributy. Metoda pro výpočet obsahu se dá dopsat, v tomto případě tu generickou optimalizuje standardní knihovna (v obecném případě je jasné, že může dělat úplně něco jiného). Prostě toto řešení právě redukuje počet atributů, které nemá smysl mít v deklaraci (a tedy paměti).


JSH

Re:Omezená dědičnost (je něco lepšího než OOP?)
« Odpověď #155 kdy: 11. 09. 2015, 15:37:24 »
Tento jazyk neznám, ale vidím tam funkci s nesmyslným názvem area(), která je vložena do nějakého rodiče obou objektů. Něco podobného dělají v PHP traits. Ovšem už ze zápisu té funkce vidím, že u čtverce zbytečně počítá cos(skew) - je vždy roven jedné.
To je právě ta pointa. Ta funkce spočítá plochu jakéhokoliv rovnoběžníka a její kód je tam jen jednou. Pro něco tak malého to nevynikne, ale pro větší kusy kódu je to jednoznačné plus. Ta nabušenost tohohle přístupu je evidentní třeba u STL v C++.
Citace
Raději napíši do každé třídy jiný vzoreček pro výpočet obsahu, než abych do třídy Čtverec dával atribut skew, který tam sémanticky vůbec nepatří. Místo jednoho atributu tam máš tři atributy - z toho dva jsou zcela zbytečné. Čtverec má jen jeden atribut a tím je délka strany.
Ale čtverec má i délku druhé strany a skew. Akorát jsou strany stejně dlouhé a skew je vždycky 0. Touhle úpravou jsi přišel o možnost použít čtverec kdekoliv, kde se dá použít obdélník nebo rovnoběžník. Tvoje verze zvládne jen ten obsah a ne všem ostatním si vyláme zuby.
Citace
Jak vidíš, zápis je ještě kratší, ještě jednodušší a pro mnohé i čitelnější.
Akorát se ztratilo veškeré sdílení kódu, což bylo to hlavní, co ten příklad ilustroval. Místo jednoho kusu kódu si ho musím u každé třídy implementovat znova a znova.

Kit

Re:Omezená dědičnost (je něco lepšího než OOP?)
« Odpověď #156 kdy: 11. 09. 2015, 15:57:30 »
1) Co je na area nesmyslného? Možná se douč AJ.

Název area() se nehodí pro název metody, protože je to podstatné jméno. Je však možné ho použít pro vlastnost Area, která by se tu docela hodila. Možná se douč pravidla pojmenování tříd, metod a vlastností.

Citace
2) Omyl, u čtverce je jen jeden atribut, zbytek jsou computed properties. To nejsou atributy. Metoda pro výpočet obsahu se dá dopsat, v tomto případě tu generickou optimalizuje standardní knihovna (v obecném případě je jasné, že může dělat úplně něco jiného). Prostě toto řešení právě redukuje počet atributů, které nemá smysl mít v deklaraci (a tedy paměti).

Jsou tam tři privátní atributy: side1, side2 a skew. Snad ještě umím počítat. Všechny tři se nachází uvnitř objektu, ale to není podstatné, stejně jako nejsou podstatné optimalizace kompilátoru. Podstatné je, že čtverec má z definice jen jednu délku strany a žádné zkosení. Ve tvém řešení silně trpí sémantika jenom proto, že se pokoušíš sdílet nějakou metodu, která ani sdílena být nemá.

zboj

  • *****
  • 1 507
    • Zobrazit profil
    • E-mail
Re:Omezená dědičnost (je něco lepšího než OOP?)
« Odpověď #157 kdy: 11. 09. 2015, 16:09:52 »
1) Co je na area nesmyslného? Možná se douč AJ.

Název area() se nehodí pro název metody, protože je to podstatné jméno. Je však možné ho použít pro vlastnost Area, která by se tu docela hodila. Možná se douč pravidla pojmenování tříd, metod a vlastností.

Citace
2) Omyl, u čtverce je jen jeden atribut, zbytek jsou computed properties. To nejsou atributy. Metoda pro výpočet obsahu se dá dopsat, v tomto případě tu generickou optimalizuje standardní knihovna (v obecném případě je jasné, že může dělat úplně něco jiného). Prostě toto řešení právě redukuje počet atributů, které nemá smysl mít v deklaraci (a tedy paměti).

Jsou tam tři privátní atributy: side1, side2 a skew. Snad ještě umím počítat. Všechny tři se nachází uvnitř objektu, ale to není podstatné, stejně jako nejsou podstatné optimalizace kompilátoru. Podstatné je, že čtverec má z definice jen jednu délku strany a žádné zkosení. Ve tvém řešení silně trpí sémantika jenom proto, že se pokoušíš sdílet nějakou metodu, která ani sdílena být nemá.

1) Přečti si konvence pojmenování metod ve Swiftu, než začneš kritizovat.
2) Je tam jeden atribut a dvě počítané vlastnosti, což je něco jako převlečená metoda. Zbytek ti vysvětlil JSH.

Pavel Tisnovsky

Re:Omezená dědičnost (je něco lepšího než OOP?)
« Odpověď #158 kdy: 11. 09. 2015, 16:14:00 »
Záleží na aplikaci, když to bude geometrický tvar v počítačové hře, tak s immutable moc nepochodíš, tvar a poloha objektů se mění neustále.
Tohle je zajímavá otázka. Je lepší mít mutable scénu, upravovat ji a řešit synchronizaci? Nebo je lepší immutable scéna, update vytvoří novou, jen zrecykluje všechno co se nezměnilo?
Já vidím to immutable řešení jako podstatně elegantnější a i celkem efektivní. A není to jen moje teoretizování. Nenašel jsem přednášku kohosi od Epicu, kde jsem to slyšel poprvé, ale něco podobného zaznělo i tu https://www.youtube.com/watch?v=1PhArSujR_A.

Tusim autor hry Iconclad :Steam Legions (psano v Clojure) se v blogu tvaril, jak se mu s immutable stavem hry strasne dobre pracovalo.

Kit

Re:Omezená dědičnost (je něco lepšího než OOP?)
« Odpověď #159 kdy: 11. 09. 2015, 16:22:03 »
Jak vidíš, zápis je ještě kratší, ještě jednodušší a pro mnohé i čitelnější.
Akorát se ztratilo veškeré sdílení kódu, což bylo to hlavní, co ten příklad ilustroval. Místo jednoho kusu kódu si ho musím u každé třídy implementovat znova a znova.

To bylo mým úmyslem. Demonstrovat, že sdílení kousíčku kódu komplikovanými nástroji je složitější a podstatně méně čitelné, než použití interface. Pokud budu někde chtít použít třídu Čtverec, budu se oprávněně ptát, k čemu má tři atributy, když mi stačí jeden. Pokud to bude složitější výpočet, než jen obsah, mohu ten vzoreček sdílet v nějaké statické třídě - podobně jako je sestavena celá třída Math.

Program musí být v prvé řadě snadno čitelný člověkem programátorem. Kompilátor je až daleko za ním. Pokud je metoda pro výpočet obsahu zapouzdřena uvnitř svého objektu, je to nejen přehledné, ale i rychlé.

1) Přečti si konvence pojmenování metod ve Swiftu, než začneš kritizovat.

Zrovna pojmenování metod tam chybí. Přitom běžně se i ve Swiftu dodržuje pravidlo, že název metody má začínat slovesem.

Citace
2) Je tam jeden atribut a dvě počítané vlastnosti, což je něco jako převlečená metoda. Zbytek ti vysvětlil JSH.

Ty dvě počítané vlastnosti jsou tam zcela zbytečné. A co je zbytečné, musí pryč.

gamer

Re:Omezená dědičnost (je něco lepšího než OOP?)
« Odpověď #160 kdy: 11. 09. 2015, 16:23:31 »
Tohle je zajímavá otázka. Je lepší mít mutable scénu, upravovat ji a řešit synchronizaci? Nebo je lepší immutable scéna, update vytvoří novou, jen zrecykluje všechno co se nezměnilo?
Já vidím to immutable řešení jako podstatně elegantnější a i celkem efektivní. A není to jen moje teoretizování. Nenašel jsem přednášku kohosi od Epicu, kde jsem to slyšel poprvé, ale něco podobného zaznělo i tu https://www.youtube.com/watch?v=1PhArSujR_A.

Immutable objekty fungují hezky v teorii, ale prakticky narazíš na to, že stejně musíš řešit synchronizaci. Dělám třeba hru, kde panáci sbírají pomeranče. Panák přijde k pomerančí ležícímu na zemi a strčí si ho do kapsy. Pomeranč je immutable. Takže co panák udělá, vytvoři novou kopii pomeranče, která je v jeho kapse. Starý pomeranč zruší. Doteď všechno v pohodě. A teď si řeknu, no jo, když mám všechno immutable a mám spoustu jader CPU, tak pustím všechny panáky paralelně a všechno bude mnohem rychlejší. Jenomže pak přijdou k jednomu pomeranči paralelně dva různí panáci. Oba ve stejný čas vytvoří kopii pomeranče ležícího na zemi a strčí si ho do kapsy. Starý pomeranč zruší. Všechno krásně funguje, akorát místo jednoho pomeranče mám dva. To není úplně přesně to, co bych chtěl.

S celou immutable scénou si to už vůbec nedovedu představit. Mám scénu na které je 50 panáků. Každý panák něco udělá a vytvoří si kopii scény. Mám 50 různých scén, každá je jiná. Co s tím budu dělat, jak dám 50 různých scén nějak deterministicky dohromady do jedné?

LSP

Re:Omezená dědičnost (je něco lepšího než OOP?)
« Odpověď #161 kdy: 11. 09. 2015, 16:26:15 »
Tohle mi přijde jakože s immutable objekty nemáš moc praktických zkušeností - z jazyků, kde se používají hodně. Protože právě immutable data nemůžou být nekonzistentní z principu, tímhle vůbec není potřeba se zabývat, tenhle problém vůbec neexistuje.

Zkušenosti mám, například když spustíš dvě vlákna a každému předáš immutable kopii tvých dat, tak po skončení vláken musíš psát extra algoritmus na sloučení výsledků. U klasické synchronizované mutable struktury tohle neřešíš.
Samozřejmě má immutable přístup svoje výhody, ale není to univerzální všelék, jsou případy kdy je to kontraproduktivní.

zboj

  • *****
  • 1 507
    • Zobrazit profil
    • E-mail
Re:Omezená dědičnost (je něco lepšího než OOP?)
« Odpověď #162 kdy: 11. 09. 2015, 16:30:57 »
Jak vidíš, zápis je ještě kratší, ještě jednodušší a pro mnohé i čitelnější.
Akorát se ztratilo veškeré sdílení kódu, což bylo to hlavní, co ten příklad ilustroval. Místo jednoho kusu kódu si ho musím u každé třídy implementovat znova a znova.

To bylo mým úmyslem. Demonstrovat, že sdílení kousíčku kódu komplikovanými nástroji je složitější a podstatně méně čitelné, než použití interface. Pokud budu někde chtít použít třídu Čtverec, budu se oprávněně ptát, k čemu má tři atributy, když mi stačí jeden. Pokud to bude složitější výpočet, než jen obsah, mohu ten vzoreček sdílet v nějaké statické třídě - podobně jako je sestavena celá třída Math.

Program musí být v prvé řadě snadno čitelný člověkem programátorem. Kompilátor je až daleko za ním. Pokud je metoda pro výpočet obsahu zapouzdřena uvnitř svého objektu, je to nejen přehledné, ale i rychlé.

1) Přečti si konvence pojmenování metod ve Swiftu, než začneš kritizovat.

Zrovna pojmenování metod tam chybí. Přitom běžně se i ve Swiftu dodržuje pravidlo, že název metody má začínat slovesem.

Citace
2) Je tam jeden atribut a dvě počítané vlastnosti, což je něco jako převlečená metoda. Zbytek ti vysvětlil JSH.

Ty dvě počítané vlastnosti jsou tam zcela zbytečné. A co je zbytečné, musí pryč.

1) Slovesem začíná, pokud nic nevrací.
2) Působíš dojmem začínajícího studenta, který ještě nechápe (nezná) souvislosti. JSH ti už vše kolem toho příkladu vysvětlil, stačí si číst jeho odpověď stále dokola ;)

JSH

Re:Omezená dědičnost (je něco lepšího než OOP?)
« Odpověď #163 kdy: 11. 09. 2015, 16:34:00 »
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?

Kit

Re:Omezená dědičnost (je něco lepšího než OOP?)
« Odpověď #164 kdy: 11. 09. 2015, 16:39:20 »
Panák přijde k pomerančí ležícímu na zemi a strčí si ho do kapsy. Pomeranč je immutable. Takže co panák udělá, vytvoři novou kopii pomeranče, která je v jeho kapse.

Ne. Vytvoříš novou kopii kapsy s pomerančem a novou kopii scény bez pomeranče. Už jsi někdy viděl panáky, kteří by vyráběli pomeranče? Zato si panák může vyměnit prázdnou kapsu (resp. měšec) za kapsu s pomerančem.