Rust vs. C++ (funkcionální vs. OOP)

Radek Miček

Re:Rust vs. C++ (funkcionální vs. OOP)
« Odpověď #60 kdy: 14. 03. 2016, 00:11:31 »
Otázka zní, proč by to měl někdo zkoušet takto naimplementovat.

Protože podle titulku se článek zabývá dědičností - tj. čekal bych příklad s dědičností, jenže příklad v článku žádnou dědičnost nepotřebuje (potřebuje určitou formu podtypového polymorfismu, ale ne dědičnost).

Spíš se primárně zabývá "expression problemem" a vychází z C++ a jeho typicky OOP přístupu.

Pak je ovšem otázkou, k čemu je článek tazateli užitečný, když se dědičností nezabývá (a proč ji má ve svém názvu).


andy

Re:Rust vs. C++ (funkcionální vs. OOP)
« Odpověď #61 kdy: 14. 03. 2016, 00:36:04 »
Myslel jsem titulek vámi odkazovaného článku, nikoliv titulek této diskuze.
Tak nějak od začátku tadu píšu, že mnoho problémů, které se v OOP řeší dědičností, lze řešit jinak, a v FP je vhodné je řešit jinak. Odkážu na článek, který názorně ukazuje jeden z takových případů. A vy si stěžujete, že na to dědičnost nebyla potřeba. Správně, nebyla. Proto jsem na ten článek odkazoval, kromě toho, že mi to na první pohled přišlo vcelku blízké tomu, co psal autor diskuze. Teď jen nechápu, co vlastně chcete říct?

Viky

Re:Rust vs. C++ (funkcionální vs. OOP)
« Odpověď #62 kdy: 14. 03. 2016, 01:50:41 »

A jéje. Zas jeden co si o sobě myslí, že je mistr světa a všechno ví a umí líp. A přitom podle toho, jak se projevuje, je zřejmé, že ještě ani neví, co všechno neví, a polovinu toho co ví, ví blbě. Ale známe takových dost. Přesně kvůli takovým vzniklo rčení "mluviti stříbro, mlčeti zlato".

Radek Miček

Re:Rust vs. C++ (funkcionální vs. OOP)
« Odpověď #63 kdy: 14. 03. 2016, 07:05:06 »
Myslel jsem titulek vámi odkazovaného článku, nikoliv titulek této diskuze.
Tak nějak od začátku tadu píšu, že mnoho problémů, které se v OOP řeší dědičností, lze řešit jinak, a v FP je vhodné je řešit jinak. Odkážu na článek, který názorně ukazuje jeden z takových případů.

Stěžuji si, že článek žádný takový případ neukazuje. Kód v C++, který autor převádí do Haskellu, dědičnost nepoužívá - článek tedy neukazuje, jak se problém, který se v OOP řeší dědičností, vyřeší v FP jinak.

andy

Re:Rust vs. C++ (funkcionální vs. OOP)
« Odpověď #64 kdy: 14. 03. 2016, 07:11:18 »

Stěžuji si, že článek žádný takový případ neukazuje. Kód v C++, který autor převádí do Haskellu, dědičnost nepoužívá - článek tedy neukazuje, jak se problém, který se v OOP řeší dědičností, vyřeší v FP jinak.

Kód: [Vybrat]
class Base
{
    public:
        virtual ~Base() {}
        virtual void step(int delta) = 0;
        virtual std::string display() const = 0;
};
class Foo : public Base
{
    public:
        Foo(const int i) : intVal_(i) {}
        // Add delta to internal state.
        void step(int delta) override { intVal_ += delta; }
        std::string display() const override { return std::to_string(intVal_); }
    private:
        int intVal_;
};
To myslíte vážně?


Radek Miček

Re:Rust vs. C++ (funkcionální vs. OOP)
« Odpověď #65 kdy: 14. 03. 2016, 07:23:57 »

Stěžuji si, že článek žádný takový případ neukazuje. Kód v C++, který autor převádí do Haskellu, dědičnost nepoužívá - článek tedy neukazuje, jak se problém, který se v OOP řeší dědičností, vyřeší v FP jinak.

Kód: [Vybrat]
class Base
{
    public:
        virtual ~Base() {}
        virtual void step(int delta) = 0;
        virtual std::string display() const = 0;
};
class Foo : public Base
{
    public:
        Foo(const int i) : intVal_(i) {}
        // Add delta to internal state.
        void step(int delta) override { intVal_ += delta; }
        std::string display() const override { return std::to_string(intVal_); }
    private:
        int intVal_;
};
To myslíte vážně?

Ano. Od Base se nedědí vůbec nic. V příkladu jde jen o to, aby ukazatele (reference) na Foo šlo bezpečně použít tam, kde jsou očekávány ukazatele (reference) na Base - jde jen o podtypový polymorfismus - dědičnost je něco jiného.

andy

Re:Rust vs. C++ (funkcionální vs. OOP)
« Odpověď #66 kdy: 14. 03. 2016, 07:50:13 »
Ano. Od Base se nedědí vůbec nic. V příkladu jde jen o to, aby ukazatele (reference) na Foo šlo bezpečně použít tam, kde jsou očekávány ukazatele (reference) na Base - jde jen o podtypový polymorfismus - dědičnost je něco jiného.
Mě to teda připadá jako typový polymorfismus, který se v C++ řeší dědičností. Vám ne?

zboj

  • *****
  • 1 507
    • Zobrazit profil
    • E-mail
Re:Rust vs. C++ (funkcionální vs. OOP)
« Odpověď #67 kdy: 14. 03. 2016, 10:56:27 »
Pokud nehodláš psát další Lens knihovnu nebo implementovat nějakou TypeInType extension v GHC, tak bych řek, že je to úplně jedno.
Takový přístup odlišuje profíka od patlala.
Hádám, že máš category theory v malíčku, viď?
Mám.

andy

Re:Rust vs. C++ (funkcionální vs. OOP)
« Odpověď #68 kdy: 14. 03. 2016, 12:58:54 »
Pokud nehodláš psát další Lens knihovnu nebo implementovat nějakou TypeInType extension v GHC, tak bych řek, že je to úplně jedno.
Takový přístup odlišuje profíka od patlala.
Hádám, že máš category theory v malíčku, viď?
Mám.
Supr. Takže mi zajisté vysvětlíš, které části category theory (oproti tomu, co ví člověk po studiu standardních knížek o haskellu) potřebuješ třeba na implementaci tohoto: https://hackage.haskell.org/package/aeson , případně, proč je toto konkrétně práce patlala, pokud budeš mít pocit, že je (a možná i oprávněně, protože autor se tváří, že zrovna teorií moc neoplývá), a jak bys to udělal nějak výrazně lépe a hlavně, jak by ti při tom pomohla znalost category theory.

uetoyo

Re:Rust vs. C++ (funkcionální vs. OOP)
« Odpověď #69 kdy: 14. 03. 2016, 16:48:21 »

Stěžuji si, že článek žádný takový případ neukazuje. Kód v C++, který autor převádí do Haskellu, dědičnost nepoužívá - článek tedy neukazuje, jak se problém, který se v OOP řeší dědičností, vyřeší v FP jinak.

Kód: [Vybrat]
class Base
{
    public:
        virtual ~Base() {}
        virtual void step(int delta) = 0;
        virtual std::string display() const = 0;
};
class Foo : public Base
{
    public:
        Foo(const int i) : intVal_(i) {}
        // Add delta to internal state.
        void step(int delta) override { intVal_ += delta; }
        std::string display() const override { return std::to_string(intVal_); }
    private:
        int intVal_;
};
To myslíte vážně?

Ano. Od Base se nedědí vůbec nic. V příkladu jde jen o to, aby ukazatele (reference) na Foo šlo bezpečně použít tam, kde jsou očekávány ukazatele (reference) na Base - jde jen o podtypový polymorfismus - dědičnost je něco jiného.

Jak je to tedy přesne s tím (pod)typovým polymorfismes v C++; tedy není implementován dědičností? Děkuji.

zboj

  • *****
  • 1 507
    • Zobrazit profil
    • E-mail
Re:Rust vs. C++ (funkcionální vs. OOP)
« Odpověď #70 kdy: 14. 03. 2016, 17:20:40 »

Stěžuji si, že článek žádný takový případ neukazuje. Kód v C++, který autor převádí do Haskellu, dědičnost nepoužívá - článek tedy neukazuje, jak se problém, který se v OOP řeší dědičností, vyřeší v FP jinak.

Kód: [Vybrat]
class Base
{
    public:
        virtual ~Base() {}
        virtual void step(int delta) = 0;
        virtual std::string display() const = 0;
};
class Foo : public Base
{
    public:
        Foo(const int i) : intVal_(i) {}
        // Add delta to internal state.
        void step(int delta) override { intVal_ += delta; }
        std::string display() const override { return std::to_string(intVal_); }
    private:
        int intVal_;
};
To myslíte vážně?

Ano. Od Base se nedědí vůbec nic. V příkladu jde jen o to, aby ukazatele (reference) na Foo šlo bezpečně použít tam, kde jsou očekávány ukazatele (reference) na Base - jde jen o podtypový polymorfismus - dědičnost je něco jiného.

Jak je to tedy přesne s tím (pod)typovým polymorfismes v C++; tedy není implementován dědičností? Děkuji.
Když Base nemá vlastnosti a všechny metody jsou virtuální, tak se nic nedědí a jde vlastně o rozhraní/protokol (jež C++ explicitně nemá).

Re:Rust vs. C++ (funkcionální vs. OOP)
« Odpověď #71 kdy: 14. 03. 2016, 17:33:18 »
Supr. Takže mi zajisté vysvětlíš, které části category theory (oproti tomu, co ví člověk po studiu standardních knížek o haskellu) potřebuješ třeba na implementaci tohoto: https://hackage.haskell.org/package/aeson , případně, proč je toto konkrétně práce patlala, pokud budeš mít pocit, že je (a možná i oprávněně, protože autor se tváří, že zrovna teorií moc neoplývá), a jak bys to udělal nějak výrazně lépe a hlavně, jak by ti při tom pomohla znalost category theory.
To je celkem zbytečná otázka, protože zboj může kdykoli (bez důkazu) tvrdit, že díky (jakékoliv) znalosti může pracovat efektivněji, čistěji, produkovat rychlejší kód atd. atd. atd. A jestli je to skutečně tak, se stejně nedozvíš, čili informační hodnota nula. A to ani nemluvím o čistém honění si trika "kdo to neumí, je opice".

Mně přijde, že ty teoretičtější znalosti se občas hodí na to, abys nevymetal některé slepé uličky. A zvlášť to platí u věcí, které běžný programátor nedělá - jako třeba návrh toho samotného jazyka. Pokud se to postaví na dobrý základ, tak je možná menší šance, že se časem zabředne do něčeho, co nikdo předem neočekával. Ale i tak se do něčeho zabředne... Na Haskellu je to celkem dobře vidět: má suprsolidní základ, motají se kolem něj supervzdělaní lidi, některé věci vyřešil velice elegantně, ale jiné jsou stejně pořád opruz ;)

Už jenom takové ty úplné základy algebry ti můžou pomoct se občas nějakému problému vyhnout - když v nějaké datové struktuře uvidíš strom, hnedka se zeptáš, jestli to stojí za ty komplikace, které s tím budou a jestli by se to radši nedalo implementovat jako nějaké pole, se kterým se bude snadněji pracovat, líp se to bude paralelizovat a skládat. Takže si díky té znalosti a jí podpořené intuici ušetříš nějaký ten opruz v budoucnu...

Myslím, že tady nikdo netvrdí, že nějaká znalost je úplně k ničemu, spíš je spor o to, jestli se vložená námaha v praxi vrátí nebo ne - a to nevyřešíš, zejména ne se zbojem...
« Poslední změna: 14. 03. 2016, 17:35:47 od Mirek Prýmek »

JSH

Re:Rust vs. C++ (funkcionální vs. OOP)
« Odpověď #72 kdy: 14. 03. 2016, 18:27:10 »
Ano. Od Base se nedědí vůbec nic. V příkladu jde jen o to, aby ukazatele (reference) na Foo šlo bezpečně použít tam, kde jsou očekávány ukazatele (reference) na Base - jde jen o podtypový polymorfismus - dědičnost je něco jiného.
Mě to teda připadá jako typový polymorfismus, který se v C++ řeší dědičností. Vám ne?
Tak pokud si odmyslím abstraktní rozhraní, tak je dědičnost potřebná jednou za uherský rok. Navíc ani v jazycích, které neumí přeposílat zprávy nebo generovat nějaké trampolíny, se dá dědičnost nahradit pomocí kompozice a abstraktních rozhraní bez nějaké bolesti.

Radek Miček

Re:Rust vs. C++ (funkcionální vs. OOP)
« Odpověď #73 kdy: 14. 03. 2016, 19:04:12 »
Ano. Od Base se nedědí vůbec nic. V příkladu jde jen o to, aby ukazatele (reference) na Foo šlo bezpečně použít tam, kde jsou očekávány ukazatele (reference) na Base - jde jen o podtypový polymorfismus - dědičnost je něco jiného.
Mě to teda připadá jako typový polymorfismus, který se v C++ řeší dědičností. Vám ne?

Podle standardu C++ máte pravdu. Standard C++ nezná pojem podtyp - zná pouze dědičnost. Ve skutečnosti však nejde o dědičnost, ale o podtypový polymorfismus.

Obecně jsou to úplně nezávislé věci (dědičností můžete vytvořit podtřídu, jenž není podtyp, a naopak můžete mít podtyp, aniž byste použil dědičnost). A v tomto konkrétním příkladě žádnou dědičnost nepotřebujete - neboť, jak psal zboj, Base neobsahuje nic, co by mělo smysl dědit - Base nijak neobohatí svou podtřídu.

Relevantní je následující charakteristika dědičnosti:

Citace
So, knowing that c* inherits from c tells us nothing about the behavior of its objects, but only about the means by which the class is defined. Inheritance carries no semantic significance, but is only a record of the history of how a class is defined.

Převzato z Practical Foundations for Programming Languages, 2. edice, strana 251.

andy

Re:Rust vs. C++ (funkcionální vs. OOP)
« Odpověď #74 kdy: 14. 03. 2016, 23:00:59 »
Citace: Mirek Prymek
Myslím, že tady nikdo netvrdí, že nějaká znalost je úplně k ničemu, spíš je spor o to, jestli se vložená námaha v praxi vrátí nebo ne - a to nevyřešíš, zejména ne se zbojem...
To je jedna věc - ale já reagoval spíš na to, že aby člověk programoval na nějaké profi úrovni FP, tak musí umět nejspíš category theory, jinak je to patlal. Přičemž ale IMO na 90% kódu knihoven, které člověk v haskellu používá, nepotřebuje znát v podstatě žádnou category theory (resp. potřebuje znát, jak to funguje prakticky, nikoliv tu teorii za tím).

Citace: Radek Miček
Podle standardu C++ máte pravdu. Standard C++ nezná pojem podtyp - zná pouze dědičnost. Ve skutečnosti však nejde o dědičnost, ale o podtypový polymorfismus.
Já s tím naprosto souhlasím. Jenomže výsledkem je, že velké množství problémů je tím pádem možné namodelovat bez využití dědičnosti, pokud se na to člověk podívá z trochu jiného úhlu pohledu. QuickSort ve funkcionálních jazycích je taky obecně tragédie, takže si můžete zoufat, jak jsou funkcionální jazyky pomalé a nepraktické - a pak použijete tuším merge sort a najednou se to chová lépe. Některé problémy se prostě v FP řeší diametrálně odlišně, některé vyřešit elegantně nedají v FP, jiné v OOP.
Ano, v jazycích typu Haskell je dědičnost poněkud problém, jenomže těch problémů, kdy je dědičnost jediná rozumná cesta, je poměrně málo.