Fórum Root.cz

Hlavní témata => Vývoj => Téma založeno: Odysseus11 12. 03. 2011, 10:06:03

Název: Triedne vs. Prototypové OOP
Přispěvatel: Odysseus11 12. 03. 2011, 10:06:03
Dobrý deň, niekde som čítal, že prototypové OOP je lepšie ako triedne. Môžete mi vysvetliť aké výhody má prototypové OOP oproti triedam? Programujem v JScripte a na žiadne zásadné výhody som zatiaľ nenarazil, na druhej strane som narazil na nedostatky, všetko je tam na viac riadkov ako v Jave a C++.
Název: Re: Triedne vs. Prototypové OOP
Přispěvatel: rooobertek 12. 03. 2011, 12:06:25
"Lepšie" je veľmi relatívne slovo. Keď niekto celý život písal v assembleri a páči sa mu to, určite mu vyhovuje viac ako triedy alebo prototypy. Rovnako ako s prehliadačmi - vo fórach stále čítam "opera je najlepšia, ostatné je iba odpad", "firefox je najlepší, ostatné je iba odpad", "chrome je najlepšie, ostatné je iba odpad"... Windows je najlepší, linux je najlepší, bsd je najlepšie... A kto má pravdu? Podľa mňa najlepšie je to, čo zrovna potrebuješ a čo ti najviac vyhovuje.

Ale k téme http://en.wikipedia.org/wiki/Prototype-based_programming#Comparison_with_class-based_models . Môžem povedať, že bez ohladu na akademické debaty, len čisto na základe skúseností s reálnym použitím tried a prototypov, je to úplne lajtr šuma fuk. Sú iné, ani jeden z týchto spôsobov nie je lepší alebo horší.
Název: Re: Triedne vs. Prototypové OOP
Přispěvatel: Logik 12. 03. 2011, 13:51:04
Rozdíl hodně závisí na tom, jak je daná dědičnost v jazyku implementovaná. Třeba dědičnost v pythonu oproti C++ je dosti jiná.

Většinou prototypová dědičnost má výhodu oproti třídní v možnosti dynamicky měnit prototyp objektu - což je silná vlastnost, když se používá dobře (a zoufalost, když špatně), výhoda v třídní dědičnosti je silná typovost (což zpravidla vede k delšímu (musí se typy uvádět) ale méně chybovému kódu).
Ale obojí jde nějak dosáhnout i v druhém typu dědičnosti - jen to tak obvykle nebývá. 
Název: Re: Triedne vs. Prototypové OOP
Přispěvatel: podlesh 12. 03. 2011, 14:31:45
Je to v podstatě stejná debata jako klasický flame staticky vs. dynamicky typované jazyky (no, ono je to celkem logické).

Je důležité si uvědomit, proč se vlastně OOP používá a co tak zásadního přináší: je to polymorfismus, který přináší vyšší úroveň abstrakce ve srovnání s procedurálními jazyky (a existují i jiné koncepty které toho dosáhnou, např. funkce vyšších řádů či makra). Protoypy nebo třídy+dědičnost už jsou jen způsoby implementace polymorfismu.
Název: Re: Triedne vs. Prototypové OOP
Přispěvatel: Odysseus11 13. 03. 2011, 06:21:48
Většinou prototypová dědičnost má výhodu oproti třídní v možnosti dynamicky měnit prototyp objektu - což je silná vlastnost


Môžeš prosím uviesť konkrétny príklad, v ktorom dynamická zmena prototypu objektu prínáša  nejaké výhody? A aké sú to vlastne výhody? Vďaka.
Název: Re: Triedne vs. Prototypové OOP
Přispěvatel: Logik 13. 03. 2011, 15:40:58
Konkrétně možnost modifikovat prototyp se může hodit, když chce člověk za běhu vytvořit novou třídu (např. s předefinovanou metodou). V běžnym jazyku to asi budu řešit tak, že v bázové třídě udělám vlastnost pointer na funkci a ona metoda bude volat ten pointer - jednotlivý instance pak budou předefinovávat ten pointer. V prototypovym jazyku nadefinuju novej prototyp ("poděděnej" z bázovýho) a změnim mu tu metodu a vytvářim objekty....
Nebo k vytváření patchů ke knihovnám, kterej nechci měnit zdrojovej kód (chci případně upgradovat a zachovač fčnost patche), ale potřebuju udělat úpravu. Není to čistý, ale někdy je to nejlepší řešení. Nebo k implementaci toho, co se v ruby nazývá mixings, popř. obecně k různýmu metaprogramování.

Pak je další hromada technik, který využívaj modifikaci prototype chain - např. jednoduchej příklad je "překrytí" prototypové metody vlastní implementací, např. různé callbacky apod. To jde sice i v neprototypových jazycích, ale v prototypovejch je to daleko elegantnější.
Název: Re: Triedne vs. Prototypové OOP
Přispěvatel: Inkvizitor 13. 03. 2011, 20:40:04
Logiku, dlouho jsem nečetl na Rootu příspěvek, který by mě doopravdy vyděsil. Až teď ten Tvůj.  ;D
Název: Re: Triedne vs. Prototypové OOP
Přispěvatel: Lado 13. 03. 2011, 20:57:17
Pekna odpoved je na tomto videu - ma to cca 20 minut a je od tvorcu jazyka Self. Velmi zaujimave a poucne - na tom videu vysvetluje preco je to tak, ak oto je, ake to ma moznosti, co s tym planovali a podobne.

video: http://ftp.squeak.org/Media/Self/Self%20the%20video.avi
Název: Re: Triedne vs. Prototypové OOP
Přispěvatel: Logik 14. 03. 2011, 09:35:26
Logiku, dlouho jsem nečetl na Rootu příspěvek, který by mě doopravdy vyděsil. Až teď ten Tvůj.  ;D
:-) a co z toho je špatně? Vím, že třeba modifikace cizích knihoven je "nestandardní" postup, pro kterej by měl mít člověk opravdu, ale opravdu důvod - ale někdy rozumější cesta není. Nebo Ty máš nějakej návrh, jak lépe modifikovat cizí knihovny? Přijde Ti lepší varianta modifikovat přímo její kód a při příštím upgradu knihovny strávit další hodiny aplikací patche a kontrolou, že vše proběhlo tak, jak má? A nebo radši tu cizí knihovnu nepoužiješ a ztrávíš x hodin psaním jejího duplikátu?

Co máš např. proti implementaci mixings už nevím vůbec :-) A pokud nic, tak jak ho budeš implementovat v jazyce, kterej to neumí nativně? (např. javascript)?
Název: Re: Triedne vs. Prototypové OOP
Přispěvatel: JS 14. 03. 2011, 09:54:27
Logiku, dlouho jsem nečetl na Rootu příspěvek, který by mě doopravdy vyděsil. Až teď ten Tvůj.  ;D

Od doby, co jsem cetl knizku http://letoverlambda.com/ (http://letoverlambda.com/), me tyhle veci uz nedesi. I kdyz prakticka pouzitelnost je IMHO ponekud sporna.
Název: Re: Triedne vs. Prototypové OOP
Přispěvatel: ondra.novacisko.cz 14. 03. 2011, 11:22:26
ale někdy rozumější cesta není. Nebo Ty máš nějakej návrh, jak lépe modifikovat cizí knihovny? Přijde Ti lepší varianta modifikovat přímo její kód a při příštím upgradu knihovny strávit další hodiny aplikací patche a kontrolou, že vše proběhlo tak, jak má?
Nedělal bych si iluze, že by tohle prototypové programování vyřešilo lépe. Pořád nestandardní úprava nezaručuje bezpečnost v budoucích verzích.

Mimochodem, z tohoto důvodů raději nepoužívám v C++ private. Protože nikdy nevím, kdy budu potřebovat využit dědičnost, abych mohl implementovat novou funkcionalitu do objektu, který s tím původně nepočítal. To už musí být nějaký extra důvod, abych kód takto uzamknul.
Název: Re: Triedne vs. Prototypové OOP
Přispěvatel: Logik 14. 03. 2011, 11:57:46
Samozřejmě, modifikace prototypu Ti nezaručí, že to bude v další verzi knihovny fungovat tak, jako v předchozí. Ale narozdíl od modifikace zdrojového kódu máš jistotu, že tvůj patch přijde na správné místo a nemusíš pamatovat na to, že ho musíš po každém updatu aplikovat (byť to rozumně napsaný makefile může zajistit, ale to je další práce).

A i pokud se fčnost knihovny změní, tak furt izolovaně napsaná funkce má větší šanci být reusabilní, než patch, popř. se lépe zandavá do nové verze knihovny.

S tím private dosti souhlasím, i když někdy opodstatněním, pokud se píše superbezpečný kód má: zaručuje, že úpravou v potomku nemůžeš rozbít funkčnost předka. Vzhledem k tomu, že ale to vyžaduje dosti velkou analýzu toho, co všechno musí být private a navíc to jak píšeš často brání modifikacím, je zisk v drtivém počtu případů menší, než přidělaná práce.
Pokud bych ale dělal knihocvnu pro houf kodérů neumětelů, tak to může ve výsledku práci ušetřit.
Název: Re: Triedne vs. Prototypové OOP
Přispěvatel: ondra.novacisko.cz 14. 03. 2011, 12:54:48
Pokud bych ale dělal knihocvnu pro houf kodérů neumětelů, tak to může ve výsledku práci ušetřit.

Pořád je tu šance, že neumětelé budou spíš objekty používat, než aby je dědili, takže protected ve většině případech postačuje
Název: Re: Triedne vs. Prototypové OOP
Přispěvatel: Sten 14. 03. 2011, 13:52:03
S tím private dosti souhlasím, i když někdy opodstatněním, pokud se píše superbezpečný kód má: zaručuje, že úpravou v potomku nemůžeš rozbít funkčnost předka. Vzhledem k tomu, že ale to vyžaduje dosti velkou analýzu toho, co všechno musí být private a navíc to jak píšeš často brání modifikacím, je zisk v drtivém počtu případů menší, než přidělaná práce.
Pokud bych ale dělal knihocvnu pro houf kodérů neumětelů, tak to může ve výsledku práci ušetřit.

private nezaručuje vůbec nic:
Kód: [Vybrat]
#define private public
IMHO je to jenom pozůstatek nedomyšleného návrhu z počátků OOP. Mě osobně by přišlo vhodnější private ve funkci současného protected a protected jako kombinace současného protected a public const (tj. potomci mají plný přístup, cizí jenom const).
Název: Re: Triedne vs. Prototypové OOP
Přispěvatel: Logik 14. 03. 2011, 14:47:07
S tim public const nemáš IMHO pravdu. Jeden z cílů, proč je to tak udělané je, aby uživatelé nepoužívali místo veřejných a zaručených metod střeva. Protože střeva se můžou klidně změnit. Používáním "nedokumentovaných" střev si zakládáš na pořádnej problém... a protected proti tomu chrání.... (nicméně někdy, např. pro účely ladění, by se to hodilo, to zas jo).

Stejně tak private má svůj smysl. Pokud máš nějakou vnitřní stavovou proměnou a chceš zajistit, aby Ti ho žádný potomek obejktu nerozbil, tak to použiješ. Něco podobného je i v o dost mladší javě (final).

Co se týče toho, co private zaručuje a nezaučuje máš pravdu, ale z tohodle pohledu v C++ nezaručuje nic vůbec nic.... Vždycky si může uživatel napsat vlastní header file.
Nicméně, ve svym headeru můžeš tudle možnost odchytit a zařvat.
Název: Re: Triedne vs. Prototypové OOP
Přispěvatel: Logik 14. 03. 2011, 18:36:27
Ještě doplním, že ale možná svým způsobem máš pravdu - velmi často takové vnitřní stavové proměnné, které je pak v potomku třeba modifikovat - ukazují na chybu návrhu. Daná funkcionalita pravděpodobně měla být "vyjmuta" z objektu jako samostatný podobjekt a přidaná agregací (a tedy bezpečně zapouzdřená a přitom snadno měnitelná)
Název: Re: Triedne vs. Prototypové OOP
Přispěvatel: Sten 15. 03. 2011, 12:35:26
S tim public const nemáš IMHO pravdu. Jeden z cílů, proč je to tak udělané je, aby uživatelé nepoužívali místo veřejných a zaručených metod střeva. Protože střeva se můžou klidně změnit. Používáním "nedokumentovaných" střev si zakládáš na pořádnej problém... a protected proti tomu chrání.... (nicméně někdy, např. pro účely ladění, by se to hodilo, to zas jo).

public const jsem myslel místo
Kód: [Vybrat]
public:
    const std::string& getName() const {
        return this->name;
    }

protected:
    std::string name;

V tomhle případě by name mohlo být dokumentované a const přístupné a nemusel bych psát getter. Na druhou stranu nechci, aby mi to někdo měnil, a const std::string name použít nemohu, protože by to znemožnilo přiřazování.

Stejně tak private má svůj smysl. Pokud máš nějakou vnitřní stavovou proměnou a chceš zajistit, aby Ti ho žádný potomek obejktu nerozbil, tak to použiješ. Něco podobného je i v o dost mladší javě (final).

Zatím jsem nikdy nepotřeboval něco skrývat před potomky (a ani před programátory, kteří mé knihovny používali). Stejně tak jsem nepochopil, k čemu je dobrý final, než naštvat programátora, který přijde po vás, že si to nemůže podědit a upravit, ale musí si to napsat celé znovu, když se vaše úžasná třída přesně nehodí jeho potřebám.

Pokud si to potomek rozbije, je to jeho zodpovědnost a jeho problém; pokud potomek sáhne do nealokované paměti, tak celý program taky spadne a je to problém toho potomka. Spíše mám opačné zkušenosti — už několikrát se mi stalo, že by se mi hodilo v konkrétním případě zasáhnout do vnitřní stavové proměnné v poděděném objektu (často cizím) a nešlo to, takže jsem tam před #include musel dát
Kód: [Vybrat]
#define private protected
Co se týče sahání do nedokumentovaných střev, tak s tím bych problém neviděl, moje objekty nedokumentovaná střeva nemají a když se nějaká střeva změní, tak se holt rozbije program (nebo překlad) stejně jako když se změní veřejné metody (stejně i změna private memberů znamená novou verzi ABI).

Třeba STL má implementation specific střeva, ale to neznamená, že by se na ně nesmělo sahat. Napadá mě jedno řešení: některá střeva označit, že jsou implementation specific, a když se je pokusíte použít implicitně (dědičností), tak by program vyvolal varování (nebo klidně i error), ale explicitně (se jménem objektu) by použít šly, takže by pořád bylo možné je upravovat:
Kód: [Vybrat]
class SomeObject
{
protected:
    specific std::string _data;
};

class Inherited
    : public SomeObject
{
public:
    void someFunc()
    {
        this->_data = "a"; // Varování, použito implicitně
        this->SomeObject::_data; // OK, použito explicitně
    }
};
Název: Re: Triedne vs. Prototypové OOP
Přispěvatel: Sten 15. 03. 2011, 12:58:56
Ještě doplním, že ale možná svým způsobem máš pravdu - velmi často takové vnitřní stavové proměnné, které je pak v potomku třeba modifikovat - ukazují na chybu návrhu. Daná funkcionalita pravděpodobně měla být "vyjmuta" z objektu jako samostatný podobjekt a přidaná agregací (a tedy bezpečně zapouzdřená a přitom snadno měnitelná)

Teď mě napadl jeden případ, kdy by to vyjmout nešlo a bylo potřeba sahat do vnitřních stavových proměnných: HTTP klient.

Běžný HTTP klient má nějakou stavovou proměnnou ukazující, jestli jestli odesílá hlavičky nebo data nebo jestli je přijímá. Samozřejmě private, do toho mu přeci nemá kdo sahat, ne?

Jenže já jsem potřeboval toho HTTP klienta upravit tak, aby umožňoval HTTP autorizaci. Nejlépe poděděním, aby se dal onen HTTP klient snadno nahradit ve funkcích, které ho přijaly referencí (ty zase byly v jiné knihovně a já neměl možnost je upravovat). A tam jsem narazil, protože pro HTTP autorizaci musíte odeslat dotaz nejméně dvakrát (v první odpovědi se dozvíte, jak vůbec autorizovat). Jak tohle chcete řešit jinak než po přečtení hlaviček zahodit odpověď, resetovat klientovi jeho vnitřní stav a poslat nový požadavek s vyplněnými autorizačními hlavičkami, ale zároveň být schopen vrátit přečtená data, pokud server HTTP autorizaci nepožaduje?
Název: Re: Triedne vs. Prototypové OOP
Přispěvatel: alefo 15. 03. 2011, 13:44:54
Stavové premenné si môžete odosielať cez premenné. Je to síce skoro ako procedurálne programovanie, ale je to thread-safe a navyše trieda môže slúžiť ako singleton.

Takto napr. funguje Spring: tam je tona tried, ktorá v stavových premenných udržuje len konfiguráciu a závislé inštancie.
Název: Re: Triedne vs. Prototypové OOP
Přispěvatel: Logik 15. 03. 2011, 13:47:31
Citace
...public const jsem myslel místo
Jenže jsou případy, kdy to z nějakého důvodu mít dokumentované nechceš (třeba právě proto, abys měl svobodu to v další verzi třídy změnit) a pak to prostě vystavit nesmíš. Proto má protected tak, jak je, smysl.
Navíc nikdy nevíš, kdy bude třeba jednoduchou vlastnost najednou nahradit komplexnější logikou (takže najednou nebude prostá proměnná stačit, protože ji např. nestihneš rozumně aktualizovat). Takže prostě z principu vystavit to jako vlastnost je špatně.

Samozřejmě, že se to v praxi často dělá, protože zabalovat každou blbinu je "zbytečná práce", nese to s sebou ale riziko toho, že si člověk přidělá práce daleko víc. Určitým řešením by byly property, to ale v tak jednoduchym jazyce jako C++ nejde udělat moc dobře zaměnitelně s s prostou hodnotou.

---

Ad úprava střev: samozřejmě, za "bezpečnost" kódu se platí. Někdy je výhodnější udělat kód bezpečnej, někdy ne. Liší se to i mj. podle metodiky vývoje a dalších hafo věcí (velikosti pracovního týmu, výši pokuty od zákazníka za chybu :-)). To, že ty to nepoužíváš (já třeba také v podstatě ne) ale neznamená, že to nemá smysl. Jen to prostě není mechanismus vhodný pro každý případ.

Co se týčen utnosti šahat do střev - pokud je knihovna kvalitně udělaná, tak by to nemělo být potřeba....
Název: Re: Triedne vs. Prototypové OOP
Přispěvatel: ondra.novacisko.cz 15. 03. 2011, 14:56:20
Namísto public const bych viděl smysl v propertách. To jsou (pro ty, co nevědí o co jde) virtuální proměnné, které maskují getter a setter. Těm se dá třeba definovat jen getter, pak fungují jako const, a přitom se jejich vnitřní hodnota může měnit.

Property pak jsou cestou, jak se zbavit getterů a setterů úplně. Nevýhodou je, že programátor pak nemá jasnou představu, co vlastně přiřazení udělá, jak je náročné a zda nemá nějaké sideefekty. Ale to je v C++ normální, a platí zlaté pravidlo, že přetížená operace by měla primárně dělat to, na co byla původně určena. Přiřazení přiřazuje, hvězdička násobí šipítka pošoupají (ať už bity, nebo do streamu)
Název: Re: Triedne vs. Prototypové OOP
Přispěvatel: Bone Flute X 15. 03. 2011, 20:35:42
Třída, potažmo instance z ní může mět různé užití, a podle toho ji postavím. Například mohu mět konfigurační třídu, která má všechny members public, páč je to jen přepravka a žádnou validaci tam neřeším. Na druhou stranu ve většině dalších kategorií tříd (jakých, teď z fleku nedám) veřejné members nepoužiju a místo nich mám gettery a settery. Zvláště v jazycích jako je C++. V případě C#, kde se již dá dělat magie, to je jiná.

Public metody slouží jako veřejné api, pro užití instancí. Protected metody slouží k předefinování vnitřních věcí, jako jsou template metody, nebo creatory a podobně a definují tedy jakési vnitřní api. Ale rozhodně to není to samé jako private metody, které slouží k schování konkrétní implementace. Tedy na příkladu, když budu implementovat nějakou třídu a v ní budou některé logické protected, nebo public metody, a pro jejich implementaci si vytvořím nějaké pomocné další metody, tak je určitě nebudu dělat protected, ale private.

Vyjádření, že všechny metody by měly být protected, když nejsou veřejné, a nepoužívat private beru jako úlet. Všechno má své místo a svůj smysl.
Název: Re: Triedne vs. Prototypové OOP
Přispěvatel: Logik 15. 03. 2011, 20:38:34
Osobně víc než property se mi líbí princip automatického generování setterů/getterů pomocí anotací. Právě kvůli tomu, že se to netváří jako něco jiného.

Obzvlášť v C++, před property se např. nedá dát referenčítko, takže nahrazení proměné pomocí property není "bezpečná" věc.
Název: Re: Triedne vs. Prototypové OOP
Přispěvatel: Inkvizitor 16. 03. 2011, 03:01:30
Už je to asi trochu out, ale dlužím odpověď na příspěvek. Modifikace cizích knihoven je hnus, ideální samozřejmě je, když lze chování změnit například v potomkovi třídy. Docela zajímavé možnosti skýtá třeba implicitní konverze ve Scale: http://paulbarry.com/articles/2009/04/17/implicit-conversions-scalas-type-safe-answer-to-rubys-open-class - to samozřejmě neřeší všechno.

Po X letech (není to římská číslice, ale skoro to sedí) s Pythonem můžu říct, že bych se některých cool dynamických vlastností rád zbavil - už asi půl roku přemýšlím, že bych napsal článek do blogu, kde bych vysvětlil, proč IMO hlavní výhoda dynamických jazyků není v jejich dynamičnosti, nýbrž že ty statické (vesměs) zaspaly dobu; v praxi jsem zažil jenom jeden jediný případ, kdy bych například chtěl měnit metody nějakého objektu - případ je zčásti srovnatelný s tou knihovnou, ale jde o online update běžícího programu.

Mixiny jsou fajn a že některé OO jazyky nepodporují ani opravdovou násobnou dědičnost ani mixiny, to je trestuhodná věc.

Já chápu, že v praxi se uplatní leccos včetně chlíváren typu goto a drsného monkey patchingu, ale ta možnost zneužití a zavlečení chyby je obrovská.

Logiku, dlouho jsem nečetl na Rootu příspěvek, který by mě doopravdy vyděsil. Až teď ten Tvůj.  ;D
:-) a co z toho je špatně? Vím, že třeba modifikace cizích knihoven je "nestandardní" postup, pro kterej by měl mít člověk opravdu, ale opravdu důvod - ale někdy rozumější cesta není. Nebo Ty máš nějakej návrh, jak lépe modifikovat cizí knihovny? Přijde Ti lepší varianta modifikovat přímo její kód a při příštím upgradu knihovny strávit další hodiny aplikací patche a kontrolou, že vše proběhlo tak, jak má? A nebo radši tu cizí knihovnu nepoužiješ a ztrávíš x hodin psaním jejího duplikátu?

Co máš např. proti implementaci mixings už nevím vůbec :-) A pokud nic, tak jak ho budeš implementovat v jazyce, kterej to neumí nativně? (např. javascript)?
Název: Re: Triedne vs. Prototypové OOP
Přispěvatel: Logik 16. 03. 2011, 12:12:54
Modifikace cizí knihovny je sice hnus, ale když objekty z té knihovny vytváří někdo, koho taky nemůžeš modifikovat, tak buďto ve výsledku přepíšeš celou knihovnu, nebo změníš tu jednu metodu "inplace". Tady to považuju i za bezpečnější variantu, protože procházet cizí knihovnu a hledat, který všechny metody vytvářej objekt A, přepsat je, aby vytvářely objekt B - a protože tim se změnila implementace dalších tříd, tak furt dokola....

Ale jinak souhlasím, todle je "extrémní technika" a člověk by ji měl použít pouze v extrémním případě - už jsem se ale setkal s případem, kdy kdybych ji mohl použít, tak by mi to ušetřilio dny práce.

S tím, že ochrana objektů je užitečná souhlasím, ale jde něco za něco. Někdy se to hodí a někdy je to na obtíž.

Jinak daleko důležitější vlastnost prototypových jazyků je možnost předefinovat danou metodu nikoli u třídy, ale u konkrétní instance. A to má hafo použití - kvůli každý blbině se nemusí definovat vlastní třída: notabene když chce člověk hromadu objektů, kdy každej z těch objektů má některý metody předefinovaný (různý validátory, callbacky apod.). Samozřejmě, že to jde obejít pomocí ukazatelů na funkce - ale prototypový přístup je jednodušší a čistší.
Další využití je např. u různých vyvýjejících se objektů: místo aby byl v metodě switch přes stav, tak se při změně stavu objektu změní patřičnej handler apod.

Výhody dynamických jazyků jsou, akorát člověk nesmí myslet staticky. Samozřejmě, když bude člověk v dynamickém jazyku programovat jako v pascalu, tak mu zbydou jen nevýhody.
Název: Re: Triedne vs. Prototypové OOP
Přispěvatel: Inkvizitor 17. 03. 2011, 10:03:07
Jinak daleko důležitější vlastnost prototypových jazyků je možnost předefinovat danou metodu nikoli u třídy, ale u konkrétní instance. A to má hafo použití - kvůli každý blbině se nemusí definovat vlastní třída: notabene když chce člověk hromadu objektů, kdy každej z těch objektů má některý metody předefinovaný (různý validátory, callbacky apod.). Samozřejmě, že to jde obejít pomocí ukazatelů na funkce - ale prototypový přístup je jednodušší a čistší.
Další využití je např. u různých vyvýjejících se objektů: místo aby byl v metodě switch přes stav, tak se při změně stavu objektu změní patřičnej handler apod.

Výhody dynamických jazyků jsou, akorát člověk nesmí myslet staticky. Samozřejmě, když bude člověk v dynamickém jazyku programovat jako v pascalu, tak mu zbydou jen nevýhody.

No tak můžu Tě ujistit, že jako v Pascalu nepíšu. Podle mě ale dynamické jazyky většinu problémů prostě obcházejí. Do pole je možné vložit za sebe reference na libovolné objekty, ale v praxi prakticky nikdy nepotřebuješ do pole vkládat libovolné objekty, ale spíš objekty z poměrně malé množiny. Daleko lepším řešením pak jsou například algebraické typy.

Řešení callbacku referencí na funkci nebo anonymní třídou mi přijde naprosto v pohodě.
Název: Re: Triedne vs. Prototypové OOP
Přispěvatel: Logik 17. 03. 2011, 13:33:00
Řešení callbackem sice jde, ale srovnej kód:

Kód: [Vybrat]
function nothing() {};
class C
   {
   void (* callback)();
   C() { callback = nothing; }
   }
oproti

Kód: [Vybrat]
class C
   {
   callback() {};
   }
Druhá možnost je daleko jednodušší a bez rizika, že zapomeneš callback inicializovat (byť v nějakém jazyku s anonymními fcemi by to asi nebyl tak velký rozdíl). Spotřeba paměti s callbackem je také větší (musíš držet všechny callbacky, ne jen ty předefinované). No a javovské anonymní třídy maj ještě složitější syntax, byť mají také své přednosti...

Vypadá to jako blbnutí o pár znacích, ale když má daná třída těch callbacků 10, každej s jinejma argumentama, ale z toho se ale reálně použije vždy tak jeden dva, tak je rozdíl v čitelnosti značnej.

Na co narážíš aritmetickými typy nevím, v každém případě směšuješ silné a slabé typování se statickým a dynamickým jazykem. Je sice pravda, že většina slabě typovaných jazyků je dynamických a vice versa, ale platit to nemusí.

PS: Já netvrdím, že to v statickém jazyce nejde, jen tvrdím, že dynamický přístup je prostě přímočařejší. Řešení s callbackem je prostě řešení "za roh", až na to, že jsou na něj všichni zvyklý a tak nám nepřipadá divný. Proč ale když měním chování objektu, tak bych měl měnit vlastnost? Proč jsou měnitelné a neměnitelné metody objektu implementovány úplně jinou technikou?
Název: Re: Triedne vs. Prototypové OOP
Přispěvatel: Inkvizitor 17. 03. 2011, 22:14:43
Ještě existuje 3. možnost a tu preferuji já; předat ukazatel (referenci v Pythonu apod.) na tu funkci přímo v konstruktoru. To zaručuje, že inicializovat nezapomeneš. V praxi se mi to velice osvědčilo. Výborné je to v Pythonu, který má lambdy atd.

O aritmetických typech jsem nemluvil, toliko o algebraických: http://en.wikipedia.org/wiki/Algebraic_data_type (http://en.wikipedia.org/wiki/Algebraic_data_type).

Co se týče statických a dynamických typových jazyků, samozřejmě, že mají výhody i nevýhody. U dynamických jazyků mi vadí hlavně to, že jejich dynamičnost většinou nelze omezit explicitní deklarací typu. Některé to, pravda, dovedou, ale u jiných to je problém.
Název: Re: Triedne vs. Prototypové OOP
Přispěvatel: Inkvizitor 17. 03. 2011, 22:22:39
Nevím, co jsi měl, Logiku, na mysli tím směšováním dynamických a slabých typových systémů. Podle definice, kterou znám já, je Python silně typový jazyk, ale moje výtka pro něj na 100% platí.
Název: Re: Triedne vs. Prototypové OOP
Přispěvatel: Logik 17. 03. 2011, 23:49:47
Předat referenci v konstruktoru můžeš, pokud je ta reference jedna. Pokud je těch callbacků x.... Někde to lze vyřešit pojmenovanými parametry, ale pořád zůstává naprosto zbytečně "nafouknutej" konstruktor a naprosto nečitelné jeho volání. Známá programátorská pravda říká, že víc než cca 3 argumenty metody znamená, že je něco špatně....

V každym případě prostě není jediný důvod, proč by měli být metody, které jdou za běhu měnit, implementované úplně jiným způsobem, než metody, které měnit nejdou.

Co se týče zaměňování, tak ty definice jsou asi různý - to co píšeš je něco mezi silnym/slabym a statickym/dynamickym typováním, podle autora. V každém případě to, že do seznamu můžeš nacpat cokoli naprosto nesouvisí s tím, jak je řešená resoluce volaných metod. Můžu mít klidně silně staticky typovanej jazyk s prototypovou dědičností a možností modifikovat objekt za běhu. Anebo jazyk v podstatě bez jakékoli typové kontroly, kterej ale modifikovat objekty za běhu neumkožňuje (např. některé verze visual basicu).
Název: Re: Triedne vs. Prototypové OOP
Přispěvatel: Inkvizitor 18. 03. 2011, 00:58:05
To není žádná známá pravda, Logiku, to je nesmysl. U konstruktorů obzvlášť.
Název: Re: Triedne vs. Prototypové OOP
Přispěvatel: Inkvizitor 18. 03. 2011, 01:02:14
A to, že některé jazyky nemají pojmenované parametry, je jejich mínus. Ty chytřejší z nich (Haskell apod.) mají aspoň record, kterým je možné dosáhnout téhož jinými prostředky.
Název: Callbacky
Přispěvatel: ondra.novacisko.cz 18. 03. 2011, 12:56:00
K těm callbackům. Já callbacky nepoužívám, raději používám interfacy. To je lepší, stejně většinou sada nějakých callbacků bývá často spojena v jeden celek, takže není nic snažšího, než místo nastavování callbacků poslat někam referenci na objekt, který implementuje dané rozhraní a je jasno.

Někdy mám pocit, že se programátoři těch různých tříd bojí. Nebojte se. Já nemám problém vytvořit třídu, která zabírá 3 řádky. Někdy tvořím třídy na jednu řádku. Třídy tvořím uvnitř tříd, uvnitř funkcí. Třída nemusí být nic velkého, v projektech mám tisíce pomocných tříd, a pokud mi už vadí, že jich je moc hodně, že znepřehledňují API, strčím je do nějakého namespace, typicky _intr nebo _internal a hned zmizí z API.

Jinak callbacky taky úplně nezavrhuju, ale často používám pointery na metody, často většinou v kombinaci v šabloně, kdy je dán jen prototyp metody a třída je definována jen jako nějaké T. To se hodí u dispatchingu, kdy simuluj dynamické typování, kdy se třeba volá metoda jménem. Chytne to dispatcher, koukne do tabulky, najde ukazatel na metodu objektu, který to implementuje, a zavolá to. V projektu mám i cosi, co nazývám "akce", to jsou malé objekty, které nesou informaci o tom, která metoda kterého objektu se má při akci zavolat. Je to opět založené na pointeru na metodu. Dalším type objektů jsou "zprávy". Ty také nesou metodu, ale
vlastní objekt dodá až volající. Klasicky nějaký hromadný dispatcher, nebo distributor, který informuje prostřednictvím zprávy nějakou kolekci objektů.

Callbacky na metody (pointery na metody) jsou podle mne mnohem užitečnější. Zajímavý je také to, že lze takto ukazovat i na virtuální metody (podiví se možná ten, kdo ví, jak jsou tato volání vlastně implementována v C++). Nicméně pořád platí, že lepší než callback je interface, pakliže to neznamená, že množství kombinací callbacků by vedlo na obrovské množství objektů implementující všechny možné kombinace (a i tam si lze pomoc šablonama)
Název: Re: Triedne vs. Prototypové OOP
Přispěvatel: Logik 18. 03. 2011, 13:02:07
Co není pravda? Že metoda s patnácti argumentama je trochu zvrhlost? Sice konstruktor je jediná výjimka, kdy to může mít opodstatnění, ale ve výsledku je daleko čitelnější jednoduchej konstruktor a následný nastavení vlastností. Srovnej
Kód: [Vybrat]
class A {
   {
   __init__(vlastnosta=1, vlastnostb=2,vlastnostc=3, vlastnostd=4, vlastnoste=5, vlastnostf=6, vlastnostg=7, vlastnosth=8, vlastnosti=9, vlastnostj=10)
             {
             self.vlastnosta=vlastnosta;
             self.vlastnostb=vlastnostb;
             self.vlastnostc=vlastnostc;
             self.vlastnostd=vlastnostd;
             self.vlastnoste=vlastnoste;
             self.vlastnostf=vlastnostf;
             self.vlastnostg=vlastnostg;
             self.vlastnosth=vlastnosth;
             self.vlastnosti=vlastnosti;
             self.vlastnostj=vlastnostj;
             }
  }
a=A(vlastnostc=1, vlastnostd=2);
s
Kód: [Vybrat]
class A:
   def __init__():
             self.vlastnosta=1;
             self.vlastnostb=2;
             self.vlastnostc=3;
             self.vlastnostd=4;
             self.vlastnoste=5;
             self.vlastnostf=6;
             self.vlastnostg=7;
             self.vlastnosth=8;
             self.vlastnosti=9;
             self.vlastnostj=10;
a=A();
a.setVlastnostc(1);
a.setVlastnostd(2);

I když uvažuju jazyk, kde se nemusí definovat proměnné, tak druhá varianta je rozhodně mnohem čitelnější. Navíc je to řešení rychlejší, neboť nemusí na stacku vytvářet všech těch 15 defaultních parametrů konstruktoru (metody setVlastnostc se inlinují, takže tam režie není).

Pokud bych bral jazyk, kde se definují vlastnosti objektu, tak je rozdíl ještě markatnější, neboť zatímco v první variantě by každá vlastnost zabrala dva řádky (jedna definice a jedna v konstruktoru) zatímco varianta dvě by si vystačila s inicializací v definici. A definice vlastností není vůbec "zbytečná věc", neboť pomocí ní lze odchytit typo v přiřazování do vlastností.

Další věc je, že pokud změním požadavky (omezení) na jednu z vlastností, stačí mi upravit setVlastnostx(). V řešení A musím upravit navíc ještě konstruktor. Takže je to i řešení náchylnější k chybám.

No a last but not least: No a klíčová je zkušenost, že zpravidla třída, kterej potřebuje v konstruktoru 15 vlastností má špatnej design: většinou jde o sloučení funkčností více entit do jedné třídy, a mělo by se to rozdělit do víc samostatnejch tříd....
PS: Nesouhlasíš-li, dej příklad objektu s 15 parametry, který je opravu nejlépe implementovat monoliticky.
Název: Re: Triedne vs. Prototypové OOP
Přispěvatel: Logik 18. 03. 2011, 13:11:24
Jo, s tím, že často vhodnější než callback je interface souhlasím.

Ale zaujalo mě, že to říká zrovna člověk píšící v C++, kde se to pomocí interfaců dělá snad nejhůř ze všech jazyků :-) (např. neexistence anonymních tříd, byť to nested classes trochu zachraňují)- ale jak vidět, C++ je mocné a jde v něm všechno snadno a rychle, jen si to holt člověk musí nejdřív sám napsat. :-)


Název: Re: Triedne vs. Prototypové OOP
Přispěvatel: ondra.novacisko.cz 18. 03. 2011, 13:24:27
Jo, s tím, že často vhodnější než callback je interface souhlasím.

Ale zaujalo mě, že to říká zrovna člověk píšící v C++, kde se to pomocí interfaců dělá snad nejhůř ze všech jazyků :-) (např. neexistence anonymních tříd, byť to nested classes trochu zachraňují)- ale jak vidět, C++ je mocné a jde v něm všechno snadno a rychle, jen si to holt člověk musí nejdřív sám napsat. :-)

Mě se líbí mýtus anonymních tříd.

Kód: [Vybrat]
void Foo::initListeners(MyObject *obj) {
 
  class AnonymousClass: public IActionListener {
  public:
     Foo &owner;
     AnonymousClass(Foo &owner):owner(owner) {}
     virtual onAction() {owner.onAction();}
  };

  obj->addActionListener(new AnonymousClass(*this));   
}


Pravda, v Javě to je kratší

Kód: [Vybrat]
void initListeners(MyObject obj) {
 
  obj.addActionListener(new ActionListener{
      public onAction() {Foo.onAction();}
  });

}

Ale jinak C++ mechanismus podobný anonymním třídám existuje.

Ale jinak souhlasím, že když si to člověk napíše, tak to jde snadno a rychle. Mám taky už dosti rozsáhlou knihovnu různých takových udělátek. Pak to nejen napíšu rychle, ale ta cena, kterou platím v jiných jazycích za tuhle vymoženost tady prostě není (nebo už je zaplacená). Abych to přirovnal k něčemu. Mohu si pořídit satelit UPC, a bez práce budu platit měsíční paušal. Nebo si koupím, namontuju, zprovozním, zaplatím jednorázově CSLink a pak budu čumět na bednu zdarma. Ano, v tom UPC je v poplatku i HBO, ale ta cena je prostě vysoká (ekvivalent v GC u Javy)
Název: Re: Triedne vs. Prototypové OOP
Přispěvatel: ondra.novacisko.cz 18. 03. 2011, 13:27:06
Omlouvám se za syntaxtické chyby v kódu (chybí tam všude void u funkcí), psal jsem to rychle, ale myslím, že to nic nemění na tom, co jsem chtěl prezentovat
Název: Re: Triedne vs. Prototypové OOP
Přispěvatel: ondra.novacisko.cz 18. 03. 2011, 13:38:57
Co není pravda? Že metoda s patnácti argumentama je trochu zvrhlost? Sice konstruktor je jediná výjimka, kdy to může mít opodstatnění, ale ve výsledku je daleko čitelnější jednoduchej

Nevýhoda toho druhého případu je ta, že program nejprve musí nastavit proměnné na jednu hodnotu a pak se ta hodnota změní. Pokud to jsou inty, tak bezevšeho, pokud to jsou třeba ikony, tak už je to trošku problém, protože si představ, že program nejprve vytvoří ikonu s nějakým výchozim obsahem a následně je mu ten obsah změněn. Samozřejmě, lze to navrhnout tak, že výchozí stav bude "nic" ale to už zasahuje do obecnosti, vyžaduje to, aby takový stav existoval. Pokud by se jednalo o obecnější objekt, pak tato podmínka je limitující (v C++ typická podmínka, že objekt musí mít defaultní konstruktor, což není vždy vhodné).

Obecně rozděluju objekty na tři základní druhy:

Ad 1) stavové objekty mají svůj vnitřní stav, a ten se po čas jejich života mění
Ad 2) jednorázově se konfigurují se jen při vzniku a dále je není možné měnit. Jediný způsob, jak je změnit je vytvořit nový objekt za pomocí toho původního
Ad 3) nesou typicky konfiguraci, nemají gettery a settery a nemají žádnou výkonnou část.

Stavové objekty jsou asi nejtypičtější. Jednorázové a readonly objekty mají obrovský užitek v MT prostředí, protože přístup do nich není třeba synchronizovat. Naopak stavové objekty se zpravidla v MT nesdílí a každý vlákno má vlastní sadu stavových objektů.

Ale abych se vrátil, právě objekty Ad 2) vyžadují inicializaci pomocí konstruktorů, takže určitě to má smysl a nezavrhoval bych to.
Název: Re: Triedne vs. Prototypové OOP
Přispěvatel: Bone Flute X 18. 03. 2011, 14:16:32
Co není pravda? Že metoda s patnácti argumentama je trochu zvrhlost? Sice konstruktor je jediná výjimka, kdy to může mít opodstatnění, ale ve výsledku je daleko čitelnější jednoduchej konstruktor a následný nastavení vlastností.
No, zásadní problém vidím v tom, že jsou to dva objekty s naprosto jiným chováním a použitím. Zatímco v prvním případě vytvářím objekt, který vyžaduje nějaké informace, v druhém případě jsou všechny informace volitelné a tudíž také můžu (a jak známo, co můžu to udělám) jej použít bez nich. Pak záleží, jestli si ty informace kontroluju, následně to vyhazuje výjimky - což ve výsledku IMHO moc čitelné není. A nebo jestli prostě vidím, že musím ten objekt nakrmit při vytvoření.
Teď porovnávej.
Název: Re: Triedne vs. Prototypové OOP
Přispěvatel: Inkvizitor 18. 03. 2011, 23:02:52
Typickými představiteli objektů, u kterých má smysl narvat mnoho parametrů do konstruktoru, jsou prvky uživatelského rozhraní. Třeba takový Button z Tkinter má volitelných parametrů přes 20. Spoustu parametrů může mít i třída, která popisuje použitý font, případně možná i pero apod. Tam fakt nemá moc smysl to kouskovat, ikdyž by to asi nějak šlo, ale bylo by to dělení za každou cenu.

Jinak souhlasím s tím, co napsal Bone Flute X; hlavní výhodu parametrizace objektu konstruktorem spatřuji v tom, že to případně sletí už při vytváření objektu nebo mi to pohlídá dokonce pylint. Ten sice umí hlídat i použití atributů, ale myslím, že ne tak spolehlivě. Další výhodou je, že většinu logiky vidím na místě, kde se objekt vytváří. Samozřejmě, čím častěji se vytvářejí instance jedné třídy, tím je ta motivace pro předávání parametrů v konstruktoru větší a naopak.

Abych to shrnul, to pravidlo tří parametrů (nikdy jsem o něm nečetl nebo jsem si ho nezapamatoval, ale existovat může) má podle mě hlavní opodstatnění opravdu v tom, že v jazycích typu C a Java parametry nelze při předávání hodnoty pojmenovat a čitelnost klesá. Jiné jazyky si s tím poradí víc než dobře a legitimní počet parametrů může v extrémním případě jít poměrně vysoko. Pokud ale nebudeme trvat na 15 a více a hranici stanovíme někde mezi 5 a 10, příkladů je možné najít mraky; připojení k databázi - např. psycopg2.connect() má maximálně 7 parametrů, subprocess.Popen() má v konstruktoru dokonce max. 13 volitelných parametrů, SMTP_SSL 6 atd. To jsou (vedle GUI) vesměs případy, kde končí OOP a jeho teorie a přichází interakce s reálným světem vně dané aplikace.
Název: Re: Triedne vs. Prototypové OOP
Přispěvatel: Logik 19. 03. 2011, 17:24:07
Ad házení výjimek, jakej je rozdíl mezi
Kód: [Vybrat]
try:
  a=b(a=1,b=2,c=3);
catch:
a
Kód: [Vybrat]
try:
  a=b();
  a.seta(1);
  a.setb(1);
  a.setc(1);
catch:
Jeden rozdíl tam přesně vidím - i když to spadne na nějakou obecnou výjimku, v případě 2) vidím, která vlastnost to způsobila, aniž bych musel lízt do definice objektu.

Další výhoda přístupu 2 je při modifikacích kódu - když budu mergovat patche, tak při přístupu 2 vidím hned a daleko lépe, co daný patch změnil. To, že každá řádka má dělat pokud možno jen jednu věc není pravidlo zbytečné (byť samozřejmě jako všechny ostatní velmi často odůvodnitelně porušitelné).

----

Objekty uživatelskýho rozhraní zpravidla maj hromadu parametrů, ale pokud člověk programuje rozumně, tak např. používá themes, takže většina těch parametrů je danejch... Stejnětak font člověk málokdy vytváří "adhoc". Samozřejmě, existují případy, kdy je třeba tydle objekty vytvářet - ale to jsou poměrně řídké výjimky.

----

Co se týče funkcí - tak samozřejmě existují funkce, kde je více argumentů opodstatněných. Ale příliš časté nejsou. Co se týče např. toho popen, tak tam např. místo předání pole deskriptorů (což by umožnilo dát subprocesu víc než jen standardní tři vstupy/výstupy) se dává každej v spešl argumentu. A navíc je to implementace "děravá", viz varování u atributů vzniklého objektu.

Dál jsou tam flagové proměnné - a to jen jiný zápis bitového pole, který pokládám za o něco vhodnější (líp se uchovává stav volání, loguje, kvůli přidání přepínače se nemusí přidávat argument fce...). Pokud nesouhlasíš, tak prostě tydle argumenty pro účely pravidla počítej jako jeden.
No a pak jsou tam dva argumenty, svázané s implementací té funkce na jednom konkrétním OS, což je poměrně úlet (až se python rozšíří na deset OS, tak tam bude těch proměnejch dvacet??).
A je to kontruktor (takže opět by to šlo rozepsat do následných volání).

No a naposled ta třída dělá x věcí (např. hraní si s deskriptorama), pro který by asi bylo výhodný udělat spešl třídu, protože hrát si s deskriptorama je potřeba i jinde a tak je užitečný, aby se to dělo jednotnym způsobem.
Takže design tý třídy za nějak extra dobrej nepovažuju.

Stejně tak psycopg2.connect() má v podstatě jeden argument - buďto řetězec, nebo struktura či asociativní pole parametrů pro spojení. Zbytek je syntax sugar  pythonu, umožněná hlavně konstrukcí **pole (jinak bych za takovoudle syntaxi "vraždil", protože si ty parametry člověk většinou schovává někde v konfiguraci v nějaké struktuře a rozbalovat je ručně je blbina).

Samozřejmě, tři (já ani nevím, jestli v originále pravidla je tři, čtyři nebo kolik, prostě "málo") je velmi striktní číslo a najdou se příklady, kdy je rozumné mít argumentů víc. Jako každé z pravidel to samozřejmě není pravidlo striktní, ale ukazuje na možné chyby v designu aplikace a když si to sám před sebou obhájím, tak ho klidně poruším. To ale nic
nemění na tom, že má velmi často pravdu....

To, jak python zachází s argumentama je úžasný, asi nejlíp z jazyků, co znám (automatické rozbalování polí, pojmenované parametry). Občas se mi ale zdá, že to vede k přílišnému "zplošťování funkcí"

----

Ondra: to je vnořená, ne anonymní třída. To, že něco pojmenuješ anonymní, tak tím ještě anonymní třídu neuděláš :-). Proto jsem psal také, že to jde nejhůř (syntax je rozvleklá, vyžaduje zbytečnej identifikátor a nedá se napsat "inplace", což vše ztěžuje čitelnost programu) a ne že to nejde.
S readonly objejkty máš samozřejmě pravdu, ale ty málokdy bývají příliš komplexní (a nebo jdou rozložit na agregaci menších komplexních objektů).

Název: Re: Triedne vs. Prototypové OOP
Přispěvatel: Bone Flute X 19. 03. 2011, 18:09:12
Ad házení výjimek, jakej je rozdíl mezi
Kód: [Vybrat]
try:
  a=b(a=1,b=2,c=3);
catch:
a
Kód: [Vybrat]
try:
  a=b();
  a.seta(1);
  a.setb(1);
  a.setc(1);
catch:
Jeden rozdíl tam přesně vidím - i když to spadne na nějakou obecnou výjimku, v případě 2) vidím, která vlastnost to způsobila, aniž bych musel lízt do definice objektu.
Co dělá objekt b? Vyhazuje výjimky, když zadáš neplatnou hodnotu? V tom případě bych použil druhou implementaci.
Vyžaduje tři povinné hodnoty? Použiju implementaci první. Umožňuje tři volitelná nastavení? Použiju druhou implementaci. To je jasné.

Problém je v tom, že ten příklad je nedostatečný. Rozepíšu ho:

Kód: [Vybrat]
def foo(a):
  return a.process() + 42

def boo(a):
  return str(a.process()) + 'ipsum'

try:
  a=b();
  a.seta(1);
  a.setb(1);
  # a.setc(1); -- zapoměl jsem
catch:
  pass # tady to projde

# nějaký kód

print boo(a) # tady je to ok.
print foo(a) # tady to vyhodí výjimku, že nejde sčítat none a 42

Snad je z toho příkladu jasné v čem je problém.
1. Chyba vznikne až někde hluboko v kódu.
2. Vznikne někdy.
3. Hláška chyby není vůbec k věci. Problém je v tom, že objekt není dostatečně inicializován, ne v tom, že se nedají sčítat none a číslo.

Řešení jsou dvě, obě jsem zmínil. Buď se v metodě process bude kontrolovat, zda jsou naplněné všechny tři proměnné, nebo se ta kontrola bude provádět v konstruktoru, a zajistí ji interpret/překladač.

Já jsem pro druhou možnost, protože je to jednodužší a kratší. Taky bych mohl prohlásit že konstruktor je od toho konstruktorem, aby vytvořil regulérní objekt.

Je tu ještě jeden scénář:
V konstruktoru přiřadím atribut objektu. Dále někde v kódu si to rozmyslím, a budu tu hodnotu chtít změnit. Vytvořím si na to setter (nějak), a ten mi bude kontrolovat, zda přiřazuji platnou hodnotu. Zpětně pak tento setter použiju v konstruktoru. zisk je v tom, že:
1. Vždy mám validní hodnotu.
2. Validaci mám na jednom místě.
3. Nemůže se mi stát, že hodnota není nastavená.
4. Nemusím tyto hodnoty dále kontrolovat.
5. Hodnoty mohu svobodně měnit i později aniž bych si to rozbil.

V případě řešení bez parametrů v konstruktoru, nesplňuji body 2,3,4. A to jen kvůli tomu, aby to nebylo moc velké.

Na závěr bych možná ještě zmínil, že imho pojmenované parametry nic neřeší. Protože já zde argumentuji, že povinné hodnoty objektu patří do konstruktoru, zatímco volitelné hodnoty objektu patří do samostatných metod/property.
Název: Re: Triedne vs. Prototypové OOP
Přispěvatel: Bone Flute X 19. 03. 2011, 18:19:12
Eh, ještě doplním, že setkal jsem se situací, kdy uvedu parametry konstruktoru jako volitelné, protože je to jednodužší na vytvoření objektu, než ho vytvořit nějak, pak zahodit a vytvořit znova. Případ, kdy by bylo vhodné dávat povinné parametry do samostatné metody si nevzpomínám.
Název: Re: Triedne vs. Prototypové OOP
Přispěvatel: Logik 19. 03. 2011, 18:37:57
Já netvrdím, že do konstruktoru nepatří nic. Samozřejmě, pokud stav objektu bez někajech hodnot nemá smysl a nejsou ani k dispozici rozumný "defaultní" hodnoty, je asi nejlepší ho inicializovat rovnou v konstruktoru. Takových hodnot ale zase zpravidla nebývá 15.....

Pokud je hodně "povinných" parametrů nějaké funkce či konstruktoru, bývá to většinou proto, že daný objekt(funkce) dělá dvě věci najedou. V tu chvíli je rozumné ten objekt rozdělit na dva (a třeba ten druhý objekt poslat do konstruktoru toho prvního).
Název: Re: Triedne vs. Prototypové OOP
Přispěvatel: omdra.novacisko.cz 19. 03. 2011, 18:58:02
Ondra: to je vnořená, ne anonymní třída. To, že něco pojmenuješ anonymní, tak tím ještě anonymní třídu neuděláš :-). Proto jsem psal také, že to jde nejhůř (syntax je rozvleklá, vyžaduje zbytečnej identifikátor a nedá se napsat "inplace", což vše ztěžuje čitelnost programu) a ne že to nejde.

Ona není vnořená, nebo tedy ne v tom typickém smyslu (vnořená třída do třídy), protože je vnořená do funkce a z vnějšího světa prakticky nereferencovatelná. Identifikátor je tam povinný, ale v zásadě nemá širší platnost než uvnitř funkce. Jo, je to větší okecávačka, ale není to limitace. Programátorské postupy z Javy lze tedy i tady uplatnit.

Mimochodem, ani v Javě anonymní třídy nejsou úplně anonymní. Jen mají nějaký náhodný identifikátor. Viz soubory class
Název: Re: Triedne vs. Prototypové OOP
Přispěvatel: Bone Flute X 19. 03. 2011, 19:26:51
Já netvrdím, že do konstruktoru nepatří nic. Samozřejmě, pokud stav objektu bez někajech hodnot nemá smysl a nejsou ani k dispozici rozumný "defaultní" hodnoty, je asi nejlepší ho inicializovat rovnou v konstruktoru. Takových hodnot ale zase zpravidla nebývá 15.....

Pokud je hodně "povinných" parametrů nějaké funkce či konstruktoru, bývá to většinou proto, že daný objekt(funkce) dělá dvě věci najedou. V tu chvíli je rozumné ten objekt rozdělit na dva (a třeba ten druhý objekt poslat do konstruktoru toho prvního).

Pak je to ok. Tvé příklady sváděly k představě, že toto nerozlišuješ.
Název: Re: Triedne vs. Prototypové OOP
Přispěvatel: Logik 20. 03. 2011, 11:27:42
ondra: jo, souhlasím, že to je už debata o drobnostech - prostě mě to C++ řešení připadá hodně krkolomný (co se týče syntaxe), to je celý. Prostě by to chtělo nějak líp pocukrovat....