abclinuxu.cz AbcLinuxu.cz itbiz.cz ITBiz.cz HDmag.cz HDmag.cz abcprace.cz AbcPráce.cz
Inzerujte na AbcPráce.cz od 950 Kč
Rozšířené hledání
×
    dnes 04:55 | Nová verze

    OpenJS Foundation, oficiální projekt konsorcia Linux Foundation, oznámila vydání verze 22 otevřeného multiplatformního prostředí pro vývoj a běh síťových aplikací napsaných v JavaScriptu Node.js (Wikipedie). V říjnu se verze 22 stane novou aktivní LTS verzí. Podpora je plánována do dubna 2027.

    Ladislav Hagara | Komentářů: 0
    dnes 04:22 | Nová verze

    Byla vydána verze 8.2 open source virtualizační platformy Proxmox VE (Proxmox Virtual Environment, Wikipedie) založené na Debianu. Přehled novinek v poznámkách k vydání a v informačním videu. Zdůrazněn je průvodce migrací hostů z VMware ESXi do Proxmoxu.

    Ladislav Hagara | Komentářů: 0
    dnes 04:11 | Nová verze

    R (Wikipedie), programovací jazyk a prostředí určené pro statistickou analýzu dat a jejich grafické zobrazení, bylo vydáno ve verzi 4.4.0. Její kódové jméno je Puppy Cup.

    Ladislav Hagara | Komentářů: 0
    včera 22:44 | IT novinky

    IBM kupuje společnost HashiCorp (Terraform, Packer, Vault, Boundary, Consul, Nomad, Waypoint, Vagrant, …) za 6,4 miliardy dolarů, tj. 35 dolarů za akcii.

    Ladislav Hagara | Komentářů: 4
    včera 15:55 | Nová verze

    Byl vydán TrueNAS SCALE 24.04 “Dragonfish”. Přehled novinek této open source storage platformy postavené na Debianu v poznámkách k vydání.

    Ladislav Hagara | Komentářů: 0
    včera 13:44 | IT novinky

    Oznámeny byly nové Raspberry Pi Compute Module 4S. Vedle původní 1 GB varianty jsou nově k dispozici také varianty s 2 GB, 4 GB a 8 GB paměti. Compute Modules 4S mají na rozdíl od Compute Module 4 tvar a velikost Compute Module 3+ a předchozích. Lze tak provést snadný upgrade.

    Ladislav Hagara | Komentářů: 0
    včera 04:44 | Nová verze

    Po roce vývoje od vydání verze 1.24.0 byla vydána nová stabilní verze 1.26.0 webového serveru a reverzní proxy nginx (Wikipedie). Nová verze přináší řadu novinek. Podrobný přehled v souboru CHANGES-1.26.

    Ladislav Hagara | Komentářů: 0
    včera 04:33 | Nová verze

    Byla vydána nová verze 6.2 živé linuxové distribuce Tails (The Amnesic Incognito Live System), jež klade důraz na ochranu soukromí uživatelů a anonymitu. Přehled změn v příslušném seznamu. Tor Browser byl povýšen na verzi 13.0.14.

    Ladislav Hagara | Komentářů: 0
    včera 04:22 | Nová verze

    Byla vydána nová verze 30.0.0 frameworku pro vývoj multiplatformních desktopových aplikací pomocí JavaScriptu, HTML a CSS Electron (Wikipedie, GitHub). Chromium bylo aktualizováno na verzi 124.0.6367.49, V8 na verzi 12.4 a Node.js na verzi 20.11.1. Electron byl původně vyvíjen pro editor Atom pod názvem Atom Shell. Dnes je na Electronu postavena celá řada dalších aplikací.

    Ladislav Hagara | Komentářů: 2
    včera 04:11 | Nová verze

    Byla vydána nová verze 9.0.0 otevřeného emulátoru procesorů a virtualizačního nástroje QEMU (Wikipedie). Přispělo 220 vývojářů. Provedeno bylo více než 2 700 commitů. Přehled úprav a nových vlastností v seznamu změn.

    Ladislav Hagara | Komentářů: 0
    KDE Plasma 6
     (72%)
     (9%)
     (2%)
     (17%)
    Celkem 734 hlasů
     Komentářů: 4, poslední 6.4. 15:51
    Rozcestník

    API/ABI kompatibilita

    12.2.2016 21:14 | Přečteno: 2338× | linux/unix | Výběrový blog | poslední úprava: 13.2.2016 00:51

    Jednu věc jsem ještě nepochopil. Když píšu v céčku a používám nebo upravuju céčkovské knihovny, tak se často řeší API a ABI kompatibilita. V rámci kompatibilních verzí musí všechno fungovat navzdory nezávislým upgradům jednotlivých komponent. Udržovat kompatibilitu v projektech k tomu uzpůsobených bývá až kouzelně jednoduché.

    Veřejné funkce se linkují podle názvu a jejich názvy mívají jednotný prefix specifický pro danou knihovnu. Přidávání nových veřejných céčkovských funkcí je tedy triviální, takže se stačí vyhnout jejich odebírání a nekompatibilním změnám. Pokud se některé API ukáže jako špatné, nechá se zastarat a vytvoří se nové. Podobně to funguje i z pluginy, kde se pomocí dlopen() a dlsym() volající doptá na existenci knohoven a symbolů podle jména.

    Stejnětak rozšiřitelné datové struktury jdou implementovat triviálně. K zachování API i ABI kompatibility stačí objekty vždy alokovat uvnitř knihovny dynamicky a volajícímu je zpřístupňovat výhradně pomocí funkcí. Uživatel tak vlastně dostává jen identifikátor, který knihovna interně používá jako pointer na objekt v paměti.

    Jenže na dost věcí se céčko považuje za těžkopádné. Spousta věcí se píše v Pythonu, který má rovněž hromadu knihoven. Tam si umím ještě nějak představit API kompatibilitu na úrovni používání objektů. Teoreticky by mělo stačit se držet stejných zásad jako u toho C, tedy neodebírat a měnit jen opatrně. Ale co když člověk používá dědičnost? Tam přece jakékoli přidání funkce vede na potenciální kolizi s odvozenou třídou.

    Jednu dobu jsem maintainoval i projekt v C++, tomu už vůbec nerozumím. Ten jazyk je v základu úplně stejně těžkopádný jako C, ne-li více, a navíc si nese své vlastní komplikace včetně těch, které jsem zmiňoval u Pythonu, který ale aspoň přináší zásadní protihodnoty.

    Jak jsou na tom další jazyky? Existuje víc jazyků, ve kterých se dají dobře psát knihovny se stabilním API a ABI? Existují takové objektově orientované jazyky? Teoreticky to jistě jde, stačí se podívat na C a třeba GObject, který drží pointery na virtuální funkce definované v různých třídách odděleně. Ale už to není taková hezká objektová syntax.

           

    Hodnocení: 88 %

            špatnédobré        

    Tiskni Sdílej: Linkuj Jaggni to Vybrali.sme.sk Google Del.icio.us Facebook

    Komentáře

    Vložit další komentář

    12.2.2016 22:00 zorro
    Rozbalit Rozbalit vše Re: ABI kompatibilita
    Nejlépe by asi bylo ujasnit si pojmy. Zřejmě se spíše ptáte na API, jaký použijete jazyk je vlastně jedno, pokud jej budete používat, tedy navrhovat a zacházet s rozhraními, rozumně. ABI, jste asi zaslechl a přimotal to k tomu, je otázkou binární kompatibility platformy, například jak předám funkci parametry (stack, registry, které k čemu...) nebo nastavím návratový kód, a řeší to za Vás kompilátor. U interpretovaného jazyka jako Python to nebudete řešit vůbec, vazby ma binární knihovny stranou, ale tak to nebudete řešit přímo. Lehčí úvod do assembleru a ono se to vytříbí. :-)
    pavlix avatar 13.2.2016 00:25 pavlix | skóre: 54 | blog: pavlix
    Rozbalit Rozbalit vše Re: ABI kompatibilita
    Na tohle asi ani nemá cenu se snažit reagovat, že.
    Já už tu vlastně ani nejsem. Abclinuxu umřelo.
    13.2.2016 10:59 smazáno | skóre: 18 | blog: smazáno
    Rozbalit Rozbalit vše Re: ABI kompatibilita
    Nema. Ten komentar psal nekdo, kdo sice ma velkou potrebu poucovat, ale neumi cist :).

    S tou dedicnosti a vlastne prakticky rozbitim API pri pridani jakekoliv metody/atributu do tridy je to zajimava poznamka. I kdyz treba v tom C++ se ti to stane pouze pokud pokud ta nova metoda bude abstract (a nebo mozna ne, nechce se mi to domyslet;)), ale v C++ zase pridani metody do tridy zmeni velikost objektu, a ABI ti to stejne rozbije ..

    Uplne souhlasim, ze toto je dalsi nevyhoda OOP, o ktere se nemluvi.
    xkucf03 avatar 13.2.2016 11:47 xkucf03 | skóre: 49 | blog: xkucf03
    Rozbalit Rozbalit vše Re: ABI kompatibilita
    Uplne souhlasim, ze toto je dalsi nevyhoda OOP, o ktere se nemluvi.

    Aha ty mluvíš o tomhle:

    I kdyz treba v tom C++ se ti to stane pouze pokud pokud ta nova metoda bude abstract (a nebo mozna ne, nechce se mi to domyslet;)), ale v C++ zase pridani metody do tridy zmeni velikost objektu, a ABI ti to stejne rozbije ..

    a ne o konfliktu jmen (#4). V tom případě je to ale nevýhoda konkrétní implementace OOP, nikoli OOP jako takového.

    Mám rád, když se lidé přou, znamená to, že vědí, co dělají, a že mají směr. Frantovo.cz, SQL-DK, Relational pipes
    pavlix avatar 13.2.2016 13:05 pavlix | skóre: 54 | blog: pavlix
    Rozbalit Rozbalit vše Re: ABI kompatibilita
    Tak jestli to správně chápu, tak všechno, o čem se bavíme je nevýhoda konkrétní implementace OOP, případě většiny implementací podle jakékoli rozumné metriky rozšířenosti. Opět poslouží GObject jako příklad implementace, která je podle mě na ABI stabilitu připravená.
    Já už tu vlastně ani nejsem. Abclinuxu umřelo.
    xkucf03 avatar 13.2.2016 13:32 xkucf03 | skóre: 49 | blog: xkucf03
    Rozbalit Rozbalit vše Re: ABI kompatibilita
    Tak jestli to správně chápu, tak všechno, o čem se bavíme je nevýhoda konkrétní implementace OOP, případě většiny implementací podle jakékoli rozumné metriky rozšířenosti.

    Tak zatím tu byla řeč o C++ (kde to problém je) a o Javě (kde to problém není). Z toho, co píšeš, mi přijde, že GOBject má blíž k té Javě. Ale stále si nevysvětlil, jak se GObject vyrovná s případem, kdy nejdřív přidáš metodu do potomka a později přibude metoda se stejnou hlavičkou do předka – jak jazyk/kompilátor/vm pozná, která událost nastala dřív a jestli jde o záměrné překrytí nebo shodu jmen?

    Mám rád, když se lidé přou, znamená to, že vědí, co dělají, a že mají směr. Frantovo.cz, SQL-DK, Relational pipes
    pavlix avatar 13.2.2016 14:10 pavlix | skóre: 54 | blog: pavlix
    Rozbalit Rozbalit vše Re: ABI kompatibilita
    Tak zatím tu byla řeč o C++ (kde to problém je)
    Ano.
    o Javě (kde to problém není)
    Není to tak dlouho, co jsi potvrdil, že v Javě problém je, protože nevyžaduje @Override.
    Ale stále si nevysvětlil, jak se GObject vyrovná s případem, kdy nejdřív přidáš metodu do potomka a později přibude metoda se stejnou hlavičkou do předka – jak jazyk/kompilátor/vm pozná, která událost nastala dřív a jestli jde o záměrné překrytí nebo shodu jmen?
    Kam tak spěcháš? Reaguju postupně a nově přidaným komentářem pokrývám všechno včetně toho, že se GObject běžně používá tak, že je z hlediska dědičnosti jen API-stable a ne ABI-stable, i když by i to šlo jednoduše zařídit.
    Já už tu vlastně ani nejsem. Abclinuxu umřelo.
    xkucf03 avatar 13.2.2016 14:52 xkucf03 | skóre: 49 | blog: xkucf03
    Rozbalit Rozbalit vše Re: ABI kompatibilita
    Není to tak dlouho, co jsi potvrdil, že v Javě problém je, protože nevyžaduje @Override.

    Ne, to jsou dvě různé věci. V C++ to nebude fungovat, ani když k žádné kolizi jmen nedojde – stačí přidat jakoukoli metodu do předka a celé se to rozbije. Nebo ne?

    V Javě je problém jen s tím, když se náhodou trefíš do stejného názvu jaký přibyl v nové verzi předka a dáš metodě jiný význam. Jsou to poměrně okrajové případy.1 V Javě tě na chybějící @Override upozorní IDE a nástroje na analýzu kódu jako na potenciální chybu. Souhlasím, že by bylo lepší, kdyby @Override anotaci vynucoval kompilátor (ale to by si zase lidi stěžovali, že jim nová Java nepřeloží staré programy, což je věc, na které si Java dost zakládá).

    [1] i s ohledem na to, že se v takových případech často používají spíše rozhraní než třídy, že jsou některé třídy final, a tudíž je dědit nelze, a že se nové metody do knihovních tříd moc nepřidávají – a zároveň když si do potomka přidáš nějakou svojí metodu, bude se jmenovat třeba setNějakýMůjSpeciálníObjekt() a jako parametr bude mít NějakáMojeSpeciálníTřída, takže kolize je vyloučena, protože v knihovní třídě se nic takového neobjeví

    Mám rád, když se lidé přou, znamená to, že vědí, co dělají, a že mají směr. Frantovo.cz, SQL-DK, Relational pipes
    pavlix avatar 13.2.2016 15:15 pavlix | skóre: 54 | blog: pavlix
    Rozbalit Rozbalit vše Re: ABI kompatibilita
    Ne, to jsou dvě různé věci. V C++ to nebude fungovat, ani když k žádné kolizi jmen nedojde – stačí přidat jakoukoli metodu do předka a celé se to rozbije. Nebo ne?
    Jo ty se vyjadřuješ k rozšiřování bez kolize jmen. Nevím, jak přesně to v C++ funguje, ale hádám, že asi dost špatně.
    V Javě je problém jen s tím, když se náhodou trefíš do stejného názvu jaký přibyl v nové verzi předka a dáš metodě jiný význam. Jsou to poměrně okrajové případy.
    Mně to při používání Pythoního multiprocessing API trvalo ani ne pár hodin, než se mi to stalo. Sice se jednalo o kolizi jmen u atributu namísto metody, ale to na věci moc nemění.
    Souhlasím, že by bylo lepší, kdyby @Override anotaci vynucoval kompilátor (ale to by si zase lidi stěžovali, že jim nová Java nepřeloží staré programy, což je věc, na které si Java dost zakládá).
    Javu nedělám, takže nemám problém se bavit jen hypoteticky. Ale tady přece nejde o to, aby něco kompilátor vynucoval, ale hlavně aby volání správně přeložil tak, aby volání z knihovního kódu používalo knihovní verzi a volání aplikačního kódu používalo aplikační verzi, pokud nastává kolize jmen a nejedná se o přepis virtuální metody.
    že se nové metody do knihovních tříd moc nepřidávají
    Nejspíš proto, že je s tím tak velký problém. To ovšem v důsledku blokuje další vývoj, pokud teda nevytvoříš novou odvozenou třídu s nějakým tím číslíčkem.
    a zároveň když si do potomka přidáš nějakou svojí metodu, bude se jmenovat třeba setNějakýMůjSpeciálníObjekt() a jako parametr bude mít NějakáMojeSpeciálníTřída, takže kolize je vyloučena, protože v knihovní třídě se nic takového neobjeví
    No nevím, já jsem třeba přidal nového člena jménem name a nazývat ho mySpecialName by mi přišlo jednak nepraktické a jednak by mohla nastat kolize, kdybych od té třídy zase dědil. To už můžou rovnou prefixovat názvem třídy a budu na tom líp.
    Já už tu vlastně ani nejsem. Abclinuxu umřelo.
    xkucf03 avatar 13.2.2016 15:36 xkucf03 | skóre: 49 | blog: xkucf03
    Rozbalit Rozbalit vše Re: ABI kompatibilita
    Javu nedělám, takže nemám problém se bavit jen hypoteticky. Ale tady přece nejde o to, aby něco kompilátor vynucoval, ale hlavně aby volání správně přeložil tak, aby volání z knihovního kódu používalo knihovní verzi a volání aplikačního kódu používalo aplikační verzi, pokud nastává kolize jmen a nejedná se o přepis virtuální metody.

    Tím bys ale právě rozbil tu kompatibilitu se starými programy – v nové Javě by se chovaly jinak než ve staré.

    Představ si, že programátor před deseti lety podědil nějakou třídu a záměrně překryl její metodu, ale nedal tam anotaci @Override. On chce, aby se všude, kde se pracuje s instancí tohoto potomka, používala jeho metoda.

    Dát tam takovouhle implicitní „chytristiku“ by bylo mnohem nebezpečnější (těžko odhalitelné chyby) než vynutit anotaci @Override (starý kód sice nepůjde přeložit, ale hned víš, kde je chyba a snadno ji opravíš).

    No nevím, já jsem třeba přidal nového člena jménem name a nazývat ho mySpecialName by mi přišlo jednak nepraktické a jednak by mohla nastat kolize, kdybych od té třídy zase dědil. To už můžou rovnou prefixovat názvem třídy a budu na tom líp.

    Členské proměnné jsou něco jiného. Když dojde ke kolizi jejich jmen, tak ti jednak IDE zobrazí varování, ale hlavně to funguje tak, že předek i potomek pracují každý se svojí proměnnou a navzájem se neovlivňují. Nehrozí tak, že by sis v potomkovi vytvořil proměnnou, později přibyla proměnná se stejným názvem v předkovi a ty jsi z potomka nežádoucím způsobem ovlivňoval chování předka.

    Mně to při používání Pythoního multiprocessing API trvalo ani ne pár hodin, než se mi to stalo. Sice se jednalo o kolizi jmen u atributu namísto metody, ale to na věci moc nemění.

    Položil bych si následující otázky:

    • Došlo k navýšení minor/major verze knihovny?
    • Otestoval jsem si program před nasazením nebo jen bezhlavě upgradoval knihovnu?
    • Používám vhodné nástroje (jazyk, IDE, analýza kódu…)?
    • Je použití dědičnosti správný návrh? Dědičnost se nehodí na vše – někdy je lepší implementovat rozhraní a/nebo použít kompozici.
    Mám rád, když se lidé přou, znamená to, že vědí, co dělají, a že mají směr. Frantovo.cz, SQL-DK, Relational pipes
    pavlix avatar 13.2.2016 15:58 pavlix | skóre: 54 | blog: pavlix
    Rozbalit Rozbalit vše Re: ABI kompatibilita
    Tím bys ale právě rozbil tu kompatibilitu se starými programy – v nové Javě by se chovaly jinak než ve staré.
    Už jsem psal, že mě to pro účely hypotetické diskuze absolutně nezajímá.
    Členské proměnné jsou něco jiného. Když dojde ke kolizi jejich jmen, tak ti jednak IDE zobrazí varování, ale hlavně to funguje tak, že předek i potomek pracují každý se svojí proměnnou a navzájem se neovlivňují. Nehrozí tak, že by sis v potomkovi vytvořil proměnnou, později přibyla proměnná se stejným názvem v předkovi a ty jsi z potomka nežádoucím způsobem ovlivňoval chování předka.
    Jak bych na tohle jenom odpověděl slušně, aby mi zase nebyla vyčítána hrubost. Odpovídáš na komentář, kde jsem popsal určitý jev a napsal jsem přesně jakým způsobem a s jakým API se stal. Ty na to reaguješ zcela nepravdivými tvrzeními, ze kterých navíc vyvozuješ, že něco takového nehrozí. Můžeš mi sám, navrhnout, jak bych měl na takovou věc reagovat?
    Já už tu vlastně ani nejsem. Abclinuxu umřelo.
    xkucf03 avatar 13.2.2016 16:06 xkucf03 | skóre: 49 | blog: xkucf03
    Rozbalit Rozbalit vše Re: ABI kompatibilita
    Už jsem psal, že mě to pro účely hypotetické diskuze absolutně nezajímá.

    Pak mluvíme o hypotetickém návrhu nějakého nového jazyka na zelené louce. V svých komentářích jsem se snažil brát aspoň trochu ohledy na reálný svět, ve kterém žijeme teď.

    kde jsem popsal určitý jev a napsal jsem přesně jakým způsobem a s jakým API se stal

    Já jsem psal o tom, jak obdobná situace vypadá v Javě. Myslel jsem, že je to z kontextu zřejmé.

    Mám rád, když se lidé přou, znamená to, že vědí, co dělají, a že mají směr. Frantovo.cz, SQL-DK, Relational pipes
    pavlix avatar 13.2.2016 16:24 pavlix | skóre: 54 | blog: pavlix
    Rozbalit Rozbalit vše Re: ABI kompatibilita
    Můj kontext a můj svět rozhodně Java není. V kontextu diskuze mě Java zajímá maximálně jako příklad jazyka, který disponuje určitými vlastnostmi, případně se na něm dají jednoduše vysvětlit vlastnosti, kterými nedisponuje.
    Já už tu vlastně ani nejsem. Abclinuxu umřelo.
    14.2.2016 00:57 jv
    Rozbalit Rozbalit vše Re: ABI kompatibilita
    No nevím, já jsem třeba přidal nového člena jménem name a nazývat ho mySpecialName by mi přišlo jednak nepraktické a jednak by mohla nastat kolize, kdybych od té třídy zase dědil. To už můžou rovnou prefixovat názvem třídy a budu na tom líp.
    presne kvuli tomuhle jsem si myslel ze se pouziva viditelnost - private,protected. Neni tomu tak?
    pavlix avatar 14.2.2016 02:48 pavlix | skóre: 54 | blog: pavlix
    Rozbalit Rozbalit vše Re: ABI kompatibilita
    Jen private, protected se v tomto ohledu neuplatní. Ale na tom nezáleží, přidával jsem public člena. Pokud člověk přidá private atribut, tak potom přidává public accessor, který ovšem trpí úplně stejným problémem.
    Já už tu vlastně ani nejsem. Abclinuxu umřelo.
    pavlix avatar 13.2.2016 13:09 pavlix | skóre: 54 | blog: pavlix
    Rozbalit Rozbalit vše Re: ABI kompatibilita
    ale v C++ zase pridani metody do tridy zmeni velikost objektu, a ABI ti to stejne rozbije ..
    Řešení změny velikosti datových struktur asi nejde řešit jinak než dynamickou alokací nebo nějakou hroznou prasárnou.
    Já už tu vlastně ani nejsem. Abclinuxu umřelo.
    13.2.2016 19:14 Jardík
    Rozbalit Rozbalit vše Re: ABI kompatibilita
    Jako přidat novou metodu můžeš, dokonce i virtuální (ale musíš ji přidat nakonec, teda alespoň co se gcc týče). Pokud jiný kompilátor toto dělá jinak, tak prostě uděláž novou třídu, co z původní dědí (taky abstraktní), tu skrytou implementaci budeš dědit z téhle, ale uživateli pořád vrátíš pointer na původní starou, kterou si kdyžtak může přetypovat na novou.
    class MyClass
    {
      virtual ~MyClass() {};
      virtual void myfunc() = 0;
    };
    
    class MyHiddenClass : public MyClass
    {
      virtual void myfunc() { /* impl */ }
    };
    
    =>
    
    class MyClass
    {
      virtual ~MyClass() {};
      virtual void myfunc() = 0;
    };
    
    class MyClassV2 : public MyClass
    {
      virtual void newfunc() = 0;
    }
    
    class MyHiddenClass : public MyClassV2
    {
      void myfunc() override { /* impl */ }
      void newfunc() override { /* impl */ }
    };
    
    pavlix avatar 13.2.2016 19:48 pavlix | skóre: 54 | blog: pavlix
    Rozbalit Rozbalit vše Re: ABI kompatibilita
    Hmm, tak to v GObject když standardním způsobem přidáš na konec, tak budeš mít pointery na virtuální metody odvozené třídy všecky posunuté. Nemáte někdo po ruce, jako to řeší gcc-c++?
    Já už tu vlastně ani nejsem. Abclinuxu umřelo.
    13.2.2016 21:02 Jardík
    Rozbalit Rozbalit vše Re: ABI kompatibilita
    Takhle, mám li třídu
    class A
    {
    public:
      virtual ~A() {}
      virtual void a();
    private:
      int a;
    };
    
    Tak generuje toto (x64):
    
    A: offset 0: pointer na první funkci ve vtable -\
       offset 8: int a;                             |
                                                    |
    A vtable vypadá takto:                          |
       offset  0: typeinfo pointer                  |
       offset  8: A::~A            <----------------/
       offset 16: deleting dtor (volá delete po dtoru)
       offset 24: A::a
    
    Pokud přidáte další virtuální funkci, a to na konec, tak se pouze přidá další pointer na konec vtable. Existující kód bude i nadále fungovat a ABI kompatibilita bude zachována, ale jen za předpokladu, že 1) buď nikde nedědím a používám jen tento původní 'interface' přes pointer objektu, co dostanu z knihovny, nebo dědím, ale v mé odvozené třídě už nemám žádné virtuální metody (překrývat existující můžu). Protože jak říkáte, kdybych v odvozené třídě měl další virtuální metody, tak by se vtable překryly a byl by průšvih:
    // po změně A v 'knihovně'
    class A
    {
    public:
      virtual ~A() {}
      virtual void a();
      virtual void b(int);
    private:
      int a;
    };
    
    A: offset 0: pointer na první funkci ve vtable -\
       offset 8: int a;                             |
                                                    |
    A vtable vypadá takto:                          |
       offset  0: typeinfo pointer                  |
       offset  8: A::~A            <----------------/
       offset 16: deleting dtor (volá delete po dtoru)
       offset 24: A::a
       offset 32: A::b
    
    // a v aplikaci, co je zkompilovaná ke staré verzi
    class B : public A
    {
    public:
      void a() override;
      virtual void c(string);
    };
    
    B: (zděděno z A)
       offset 0: pointer na první funkci ve vtable -\
       offset 8: int a;                             |
       (B nic)                                      |
                                                    |
    B vtable vypadá takto:                          |
       offset  0: typeinfo pointer                  |
       offset  8: B::~B            <----------------/
       offset 16: deleting dtor (volá delete po dtoru)
       offset 24: B::a
       offset 32: B::c
    
    Jak vidíte, problém, protože když teď předám objekt B do nové verze knihovny (jako A), tak ta teď bude volat v případě A::b špatnou funkci B::c, která je úplně jiná.

    Takže přidat možná, s rozmyslem a jen tehdy, pokud vím, jak je rozhraní použito, nebo vím, že nemůže být použito jinak (např. zakážu dědit přes private ctor).
    pavlix avatar 13.2.2016 22:44 pavlix | skóre: 54 | blog: pavlix
    Rozbalit Rozbalit vše Re: ABI kompatibilita
    Hmm. Takže stejný problém jako s GObject, akorát GObject je podstatně flexibilnější a pokud by člověk chtěl, tak umožňuje se problému zcela vyhnout. Narozdíl od C++ je tam leccos řešeno spíše explicitně podle konvence než že by to bylo schované do implementace OOP. Takže stačí místo jedné funkce přidat odkaz na celou tabulku a ta už může být nafukovací.
    Já už tu vlastně ani nejsem. Abclinuxu umřelo.
    13.2.2016 23:57 Jardík
    Rozbalit Rozbalit vše Re: ABI kompatibilita
    Jinak podobně, jako řeší GObject 'private' (tj ten private pointer a implementace ho pak používá k přístupu ke členům) to řeší Objective-C s non-fragile ABI. Tam pak jdou i přidávat metody, jak chcete, více méně, aniž by se rozbilo ABI. Vlastně všechny metody v Objective-C se dají nazvat virtuální. Při volání metody se tam prolejzá hash tabulka podle jména metody v celé hiearchii tříd a když se najde, tak se zavolá. Je to samozřejmě jistý overhead (větší než virtual fce v C++), ale dává to jisté možnosti. To jen tak pro zajímavost.
    pavlix avatar 14.2.2016 02:50 pavlix | skóre: 54 | blog: pavlix
    Rozbalit Rozbalit vše Re: ABI kompatibilita
    To zní zajímavě. Očividně alespoň někde nezaspali a postavili bezpečný objektový model. Teda pokud ještě správně implementují ten private prostor.
    Já už tu vlastně ani nejsem. Abclinuxu umřelo.
    14.2.2016 00:24 smazáno | skóre: 18 | blog: smazáno
    Rozbalit Rozbalit vše Re: ABI kompatibilita
    s/abstract/virtual/
    12.2.2016 22:40 Odin1918 | skóre: 6 | blog: Valhalla
    Rozbalit Rozbalit vše Re: ABI kompatibilita
    Myslim, ze staci dusledne dodrzovat SRP a OCP principy a nemenit stabilni api/abi. Jestli se jedna o c, c++, javu, je imho irelevantni.
    pavlix avatar 13.2.2016 00:30 pavlix | skóre: 54 | blog: pavlix
    Rozbalit Rozbalit vše Re: ABI kompatibilita
    Zjevně to irelevantní není, když lze v C libovolně rozšiřovat API a jinde je to problém. SRP k tomuhle podle mě nemá vůbec co říct. OCP se mi právě zdá omezující ve srovnání s tím, co se dá běžně v céčkovských knihovnách bezbolestně dělat.
    Já už tu vlastně ani nejsem. Abclinuxu umřelo.
    12.2.2016 22:52 x
    Rozbalit Rozbalit vše Re: ABI kompatibilita
    Tak příkladně v Javě je binární kompatibilita definovaná přímo specifikací jazyka: https://docs.oracle.com/javase/specs/jls/se8/html/jls-13.html
    pavlix avatar 13.2.2016 00:24 pavlix | skóre: 54 | blog: pavlix
    Rozbalit Rozbalit vše Re: ABI kompatibilita
    Tam se tvrdí, že člověk může bezpečně přidávat metody, ale podle toho, co píše Franta, to není pravda.
    Já už tu vlastně ani nejsem. Abclinuxu umřelo.
    13.2.2016 08:59 x
    Rozbalit Rozbalit vše Re: ABI kompatibilita
    No, tam se tvrdí, že přidání metody je binárně kompatibilní, což je. Může to vést ke změně chování, ale co taky nemůže, že.
    pavlix avatar 13.2.2016 13:14 pavlix | skóre: 54 | blog: pavlix
    Rozbalit Rozbalit vše Re: ABI kompatibilita
    No, tam se tvrdí, že přidání metody je binárně kompatibilní, což je.
    Možná podle nějaké hodně nepraktické definice. Jinak není zjevně kompatibilní ani zdrojově, když může přidání metody vést ke kolizi se jménem, které vzniklo nezávisle za zcela odlišným účelem. Ale to už níže Franta potvrdil.
    Může to vést ke změně chování
    Irelevantní.
    Já už tu vlastně ani nejsem. Abclinuxu umřelo.
    xkucf03 avatar 13.2.2016 13:40 xkucf03 | skóre: 49 | blog: xkucf03
    Rozbalit Rozbalit vše Re: ABI kompatibilita
    Jinak není zjevně kompatibilní ani zdrojově, když může přidání metody vést ke kolizi se jménem, které vzniklo nezávisle za zcela odlišným účelem.

    Můžeš napsat nějaký konstruktivní návrh, jak by sis dědičnost představoval?

    Obávám se, že některé problémy dědičnosti jsou z principu neřešitelné. A pohoršovat se nad tím, jak Java (ne)řeší neřešitelné problémy, nedává nejmenší smysl.

    Někteří programátoři/architekti z těchto důvodů dědičnost úplně odmítají a jdou pouze cestou kompozice. Já takhle striktní nejsem, dědičnost mám celkem rád a myslím, že má svoje uplatnění, ale je třeba si být vědom těch úskalí. Mj. proto se taky často ve veřejných API používají rozhraní nikoli třídy, případně se používají final třídy, které nejde podědit (např. String v Javě).

    Mám rád, když se lidé přou, znamená to, že vědí, co dělají, a že mají směr. Frantovo.cz, SQL-DK, Relational pipes
    pavlix avatar 13.2.2016 14:10 pavlix | skóre: 54 | blog: pavlix
    Rozbalit Rozbalit vše Re: ABI kompatibilita
    Můžeš napsat nějaký konstruktivní návrh, jak by sis dědičnost představoval?
    Můžeš přestat spamovat diskuzi dokola stejným dotazem, ke kterému jsem se pouze musel propracovat? Odpovídám lineárně, na jeden komentář za druhým, máš s tím nějaký problém? :)
    Mj. proto se taky často ve veřejných API používají rozhraní nikoli třídy, případně se používají final třídy, které nejde podědit (např. String v Javě).
    To dává smysl. Jestli jsem se v tom správně zorientoval, tak se na to dá nahlížet buď tak, že dědit třídu knihovního API je vždycky špatně, nebo tak, že se do třídy knihovního API nikdy nesmí přidat nová non-private metoda. Jinak kolize hrozí.
    Já už tu vlastně ani nejsem. Abclinuxu umřelo.
    xkucf03 avatar 13.2.2016 14:32 xkucf03 | skóre: 49 | blog: xkucf03
    Rozbalit Rozbalit vše Re: ABI kompatibilita
    se do třídy knihovního API nikdy nesmí přidat nová non-private metoda. Jinak kolize hrozí.

    Omezil bych to na „v rámci stejné minor verze“ (viz #30). Potom souhlas.

    dědit třídu knihovního API je vždycky špatně

    Vždy ne, stačí používat to sémantické verzování a správně deklarovat závislosti.

    A nakonec je i otázka, jestli chceme usilovat o absolutně neprůstřelný systém, kde nemůže dojít k náhodné kolizi ani v 0,00001 % případů a jestli chceme mít možnost bez jakékoli kontroly upgradovat verzi knihovny a nasadit to hned do produkce. IMHO je rozumným kompromisem tohle dělat u patch verzí – tam je to důležité – přijde bezpečnostní oprava, chci upgradovat hned a ne řešit nějakou nekompatibilitu. Ale pokud se zvyšuje minor verze (o major ani nemluvě), tak by se kompatibilita měla otestovat a ne jen slepě věřit, že to bude fungovat – měl by to otestovat jednak někdo v distribuci (resp. chtělo by to automatické testy) a jednak ten, kdo ten systém provozuje – u kritických systémů to nasadí nejdřív na testovací prostředí a tam to nechá nějakou dobu běžet.

    Mám rád, když se lidé přou, znamená to, že vědí, co dělají, a že mají směr. Frantovo.cz, SQL-DK, Relational pipes
    pavlix avatar 13.2.2016 15:29 pavlix | skóre: 54 | blog: pavlix
    Rozbalit Rozbalit vše Re: ABI kompatibilita
    Omezil bych to na „v rámci stejné minor verze“ (viz #30). Potom souhlas.
    Kontext je zřejmý, v rámci kompatibilní verze, jinak to jenom komplikuješ, v mnohých projektech jsou mezi sebou kompatibilní i verze, které se nazývají minor, nemusíme hned specifikovat verzovací schéma, víme přece, o čem se bavíme.
    Vždy ne, stačí používat to sémantické verzování a správně deklarovat závislosti.
    To je ta druhá možnost, nikdy nerozšiřovat původní třídu a namísto toho vytvořit její novou verzi, ale to mi zatím subjektivně přijde docela divoké.
    Já už tu vlastně ani nejsem. Abclinuxu umřelo.
    xkucf03 avatar 13.2.2016 15:39 xkucf03 | skóre: 49 | blog: xkucf03
    Rozbalit Rozbalit vše Re: ABI kompatibilita

    Jen pro pořádek: tohle #30#21 jsou dvě úplně jiné věci (jednou verzování modulů, podruhé verzování jednotlivých tříd).

    Mám rád, když se lidé přou, znamená to, že vědí, co dělají, a že mají směr. Frantovo.cz, SQL-DK, Relational pipes
    pavlix avatar 13.2.2016 16:18 pavlix | skóre: 54 | blog: pavlix
    Rozbalit Rozbalit vše Re: ABI kompatibilita
    V tom bych žádnou nejasnost nehledal.
    Já už tu vlastně ani nejsem. Abclinuxu umřelo.
    13.2.2016 15:54 x
    Rozbalit Rozbalit vše Re: ABI kompatibilita
    Definice je v tom dokumentu uvedená:
    A change to a type is binary compatible with (equivalently, does not break binary compatibility with) pre-existing binaries if pre-existing binaries that previously linked without error will continue to link without error.
    Jak moc je či není praktická...

    Jinak změna klidně může být zdrojově nekompatibilní a přitom být binárně kompatibilní, takže tohle by stálo za to rozlišovat.
    pavlix avatar 13.2.2016 16:14 pavlix | skóre: 54 | blog: pavlix
    Rozbalit Rozbalit vše Re: ABI kompatibilita
    A change to a type is binary compatible with (equivalently, does not break binary compatibility with) pre-existing binaries if pre-existing binaries that previously linked without error will continue to link without error.
    Tak linkovat to bude, ale jde o to, která metoda se bude z knihovny volat.
    Jinak změna klidně může být zdrojově nekompatibilní a přitom být binárně kompatibilní, takže tohle by stálo za to rozlišovat.
    Rozhodně.
    Já už tu vlastně ani nejsem. Abclinuxu umřelo.
    14.2.2016 10:37 x
    Rozbalit Rozbalit vše Re: ABI kompatibilita
    Tak linkovat to bude, ale jde o to, která metoda se bude z knihovny volat.
    Když jsou všechny metody virtuální, tak samozřejmě ta z potomka, že.

    C# je v tomhle trochu zajímavější: tam nejen že metody nejsou ve výchozím stavu virtuální (musí se přidat klíčové slovo virtual), ale potomek může metodu z předka namísto překrytí (jen u virtuálních metod, klíčové slovo override) i zastínit (mělo by se použít klíčové slovo new, jinak to vede na warning). Bohužel jak tam funguje binární kompatibilita netuším.
    pavlix avatar 14.2.2016 13:10 pavlix | skóre: 54 | blog: pavlix
    Rozbalit Rozbalit vše Re: ABI kompatibilita
    Když jsou všechny metody virtuální, tak samozřejmě ta z potomka, že.
    Což je v případě shody jmen chyba.
    C# je v tomhle trochu zajímavější: tam nejen že metody nejsou ve výchozím stavu virtuální (musí se přidat klíčové slovo virtual), ale potomek může metodu z předka namísto překrytí (jen u virtuálních metod, klíčové slovo override) i zastínit (mělo by se použít klíčové slovo new, jinak to vede na warning). Bohužel jak tam funguje binární kompatibilita netuším.

    A může virtuální metodu zastínit nová virtuální metoda? Nedělám v C#, takže se omlouvám, jestli je to hloupý dotaz, jestli jsou například všechny metody virtuální.

    Tohle by mohlo zajímat Frantu, který zde mluvil o @Override, leccos by se vyřešilo, kdyby jazyky zavedly doporučení uvádět u všech virtuálních metod uvádět buď @New nebo @override. Radši rovnou upozorním, že opět mluvím především o konceptu, nikoliv o konkrétní syntaxi. Nové kompilátory by mohly varovat, pokud se u virtuální metody explicitně neurčí překrytí/zastínění.

    Jinak slyšel jsem od pár lidí, že se C# odkolnil od Javy dobrým směrem a klíčové slovo new tomu zrovna nasvědčuje.
    Já už tu vlastně ani nejsem. Abclinuxu umřelo.
    14.2.2016 13:46 Ondrej Santiago Zajicek
    Rozbalit Rozbalit vše Re: ABI kompatibilita
    leccos by se vyřešilo, kdyby jazyky zavedly doporučení uvádět u všech virtuálních metod uvádět buď @New nebo @override.

    Nektere pripady do resi, ale rozhodne ne vsechny. Napr. situaci, kdy program pouziva tridu B z knihovny libB, ktera je potomkem tridy A z knihovny libA. Trida A zavede nejakou metodu s @new, program pro na sve objekty zacne volat tuto metodu a nasledne nova verze knihovny B zavede metodu stejneho jmena take s @new. Program pak bude volat metodu z libB, prestoze zamerem bylo volat metodu z libA. A to bez jedineho warningu.
    pavlix avatar 14.2.2016 14:48 pavlix | skóre: 54 | blog: pavlix
    Rozbalit Rozbalit vše Re: ABI kompatibilita
    Hmm, v tomhle je to slabší než anotace konkrétní původní třídou. Skoro to vypadá, že by bylo nejlepší namísto @Override dekorovat vždy specifikací konkrétní původní třídy, jako tomu je u GObject, něco na způsob @New by pomohlo jenom v případě řešení zpětné kompatibility, aby absence anotace nemusela být povinná.

    Pokud jsem na něco nezapomněl, tak už zbývá jen zjistit, jestli je někde něco takového implementováno.
    Já už tu vlastně ani nejsem. Abclinuxu umřelo.
    xkucf03 avatar 12.2.2016 22:58 xkucf03 | skóre: 49 | blog: xkucf03
    Rozbalit Rozbalit vše Java

    Java (případně okořeněná OSGi).

    Ale co se týče dědičnosti a kolize s názvu metody s poděděnou třídou – to je víceméně neřešitelný problém z principu – kompilátor/VM nepozná, jestli jsi metodu překryl záměrně nebo jestli jsi ji měl napsanou dříve a teď jsi jen upgradoval knihovnu předka, ve které je stejně pojmenovaná metoda.

    Leda vyžadovat anotaci @Override (dnes je jen doporučená a ochrání tě jen před opačným problémem – když ji tam dáš a v předkovi taková metoda nebude, považuje se to za chybu).

    Mám rád, když se lidé přou, znamená to, že vědí, co dělají, a že mají směr. Frantovo.cz, SQL-DK, Relational pipes
    12.2.2016 23:26 dementni.lojzik | skóre: 19 | blog: ze zivota na vsi
    Rozbalit Rozbalit vše Re: Java
    Leda vyžadovat anotaci @Override
    napr. Scala ji vyzaduje
    xkucf03 avatar 13.2.2016 11:49 xkucf03 | skóre: 49 | blog: xkucf03
    Rozbalit Rozbalit vše Re: Java
    To mi přijde rozumné. Ale v Javě se to asi neprosadí, protože by to rozbilo kompatibilitu se spoustou starých programů.
    Mám rád, když se lidé přou, znamená to, že vědí, co dělají, a že mají směr. Frantovo.cz, SQL-DK, Relational pipes
    pavlix avatar 13.2.2016 00:22 pavlix | skóre: 54 | blog: pavlix
    Rozbalit Rozbalit vše Re: Java
    Ale co se týče dědičnosti a kolize s názvu metody s poděděnou třídou – to je víceméně neřešitelný problém z principu – kompilátor/VM nepozná, jestli jsi metodu překryl záměrně nebo jestli jsi ji měl napsanou dříve a teď jsi jen upgradoval knihovnu předka, ve které je stejně pojmenovaná metoda.
    Mně to napadlo právě proto, že v C ten problém nenastává. Ani při rozumném použití GObject.
    Leda vyžadovat anotaci @Override
    To by znělo jako řešení, jen přemýšlím, jen popravdě nedomýšlím, jak by tohle fungovalo v ABI u kompilovaného jazyka.
    Já už tu vlastně ani nejsem. Abclinuxu umřelo.
    xkucf03 avatar 13.2.2016 12:05 xkucf03 | skóre: 49 | blog: xkucf03
    Rozbalit Rozbalit vše Re: Java
    Mně to napadlo právě proto, že v C ten problém nenastává.

    Když nemá dědičnost, tak asi ne :-)

    Ani při rozumném použití GObject.

    Jak to tam funguje? Co když do předka předám stejnou metodu, jako někdo přidal do potomka? Dojde k nechtěnému překrytí metody? Nebo to nejde?

    Jak GObject pozná, jestli šlo o záměr programátora nebo neúmyslnou shodu?

    Mám rád, když se lidé přou, znamená to, že vědí, co dělají, a že mají směr. Frantovo.cz, SQL-DK, Relational pipes
    pavlix avatar 13.2.2016 13:49 pavlix | skóre: 54 | blog: pavlix
    Rozbalit Rozbalit vše Re: Java
    Teď přemýšlím, jestli je přidání metody opravdu bezpečné a z hlediska ABI. A vypadá to, že není, kvůli problému s velikostní, na který upozorňoval little.owl, ale je to zřejmě designová volba, stačilo by vždy používat samostatnou tabulku virtuálních funkcí pro každou třídu. Škoda.

    Ale z hlediska API to mají podchycené. Neexistuje žádný sdílený namespace, kde by k tomu mohlo dojít. Takže pojem „stejná metoda“ ztrácí význam a tudíž se ti něco takového nemůže stát. Bavíme se teda o céčku, automaticky generované bindingy s tím můžou ještě zamíchat.

    Tabulka virtuálních metod je kaskádová. Když vytváříš novou třídu, tak je ta třída v paměti realizována objektem typu struct, který mimo jiné obsahuje i objekt pro nadřazenou třídu. Tak to jde až po třídu nejvyšší úrovně. Takže zatímco nová virtuální metoda pointer na funkci dostupný přes my_class.my_method, stejně pojmenovaná zděděná virtuální metoda je dostupná přes my_class.parent.my_method, případně pomocí přetypování. Každopádně je pointer na funkci uložený na jiné relatiní adrese k začátku struktury.

    V implementaci, která hledá funkce podle jména, bys téhož výsledku dosáhl prefixováním každého jména názvem třídy. Tady je to ale přecijen řešeno o něco elegantněji.
    Já už tu vlastně ani nejsem. Abclinuxu umřelo.
    xkucf03 avatar 13.2.2016 14:15 xkucf03 | skóre: 49 | blog: xkucf03
    Rozbalit Rozbalit vše Dědičnost, překrývání metod
    Ale z hlediska API to mají podchycené. Neexistuje žádný sdílený namespace, kde by k tomu mohlo dojít. Takže pojem „stejná metoda“ ztrácí význam a tudíž se ti něco takového nemůže stát.

    Takže neexistuje nic jako překrýt metodu předka v potomkovi? Pak ten problém nastat nemůže, ale nejde pak ani o dědičnost, o které se tu bavíme – např. v Javě můžeš překrýt v potomkovi metodu předka, aby se chovala jinak, a předat instanci potomka kódu, který umí pracovat s předkem – a tento kód zavolá tvoji překrytou metodu s jiným chováním (např. jsi tam přidal logování nebo nějaké vylepšení), aniž by o tom musel vědět (myslí si, že pracuje s předkem, resp. neřeší to).

    V implementaci, která hledá funkce podle jména, bys téhož výsledku dosáhl prefixováním každého jména názvem třídy. Tady je to ale přecijen řešeno o něco elegantněji.

    Pak by ale nešlo překrývat metody předka v potomkovi, protože volající kód by musel vědět, kterou metodu chce volat (jestli předka nebo potomka).

    Mám rád, když se lidé přou, znamená to, že vědí, co dělají, a že mají směr. Frantovo.cz, SQL-DK, Relational pipes
    pavlix avatar 13.2.2016 14:29 pavlix | skóre: 54 | blog: pavlix
    Rozbalit Rozbalit vše Re: Dědičnost, překrývání metod
    Takže neexistuje nic jako překrýt metodu předka v potomkovi?
    Napíšeš novou funkci a uložíš ji do příslušného pointeru. Různé odvozené třídy pak mají na dané pozici různé funkce.
    Pak by ale nešlo překrývat metody předka v potomkovi, protože volající kód by musel vědět, kterou metodu chce volat (jestli předka nebo potomka).
    Při překrývání musíš samozřejmě prefix zachovat.
    Já už tu vlastně ani nejsem. Abclinuxu umřelo.
    pavlix avatar 13.2.2016 22:53 pavlix | skóre: 54 | blog: pavlix
    Rozbalit Rozbalit vše Re: Dědičnost, překrývání metod
    Mimochodem, když už jsme u toho, tak GObject umí i interfaces, která jsou rovněž realizovaná jako seznam pointerů na funkce. Interfaces se registrují při vytváření třídy. Sice neznám detaily implementace, ale fungují tak jak mají, tzn. žádný problém s kompatibilitou nevytvářejí.
    Já už tu vlastně ani nejsem. Abclinuxu umřelo.
    13.2.2016 00:24 kverulant
    Rozbalit Rozbalit vše Re: ABI kompatibilita
    Vzhledem k tou že ani C nemá standardizované ABI, je celý blog úplně mimo mísu.

    Ale k tématu. Udržovat knihovnu v jakémkoliv jazyce, tak aby s tím byli její uživatelé spokojení, je zatraceně těžká věc. Doporučuju knížku od Jaroslava Tulacha API design (vlastně vychází ze zkušeností práce na netbeans platformě).
    pavlix avatar 13.2.2016 00:49 pavlix | skóre: 54 | blog: pavlix
    Rozbalit Rozbalit vše Re: ABI kompatibilita
    Vzhledem k tou že ani C nemá standardizované ABI, je celý blog úplně mimo mísu.

    Vzhledem k tomu, že je řeč o ABI knihoven, mám obavu, že jsou mimo mísu jen některé komentáře.
    Udržovat knihovnu v jakémkoliv jazyce, tak aby s tím byli její uživatelé spokojení, je zatraceně těžká věc.
    To je všechno hezké, ale zkusím diskuzi trochu vrátit do kontextu. V binárních linuxových distribucích je relativně běžné upgradovat komponentu, na které je závislá jiná komponenta. A v případě céčkovských knihoven není problém dodávat funkcionalitu aniž by bylo potřeba upravovat nebo dokonce jenom rebuildovat tu závislou komponentu. Co se tak pohybuju mezi céčkovými linuxovými vývojáři, tak to zpravidla berou jako samozřejmost a přitom to skoro vypadá, že touto možností z jazyků běžně v linuxových distrech používaných disponuje jenom C.
    Já už tu vlastně ani nejsem. Abclinuxu umřelo.
    13.2.2016 00:31 kverulant
    Rozbalit Rozbalit vše Re: ABI kompatibilita
    Edit: ta kniha se jmenuje Practical API Design: Confessions of a Java Framework Architect
    pavlix avatar 13.2.2016 15:16 pavlix | skóre: 54 | blog: pavlix
    Rozbalit Rozbalit vše Re: ABI kompatibilita
    Čím dál tím víc mě začíná zajímat. Jenom doufám, že ta kniha není úplně specifická pro Javu, ve které dost možná nikdy nic dělat nebudu.
    Já už tu vlastně ani nejsem. Abclinuxu umřelo.
    13.2.2016 01:44 pc2005 | skóre: 38 | blog: GardenOfEdenConfiguration | liberec
    Rozbalit Rozbalit vše Re: API/ABI kompatibilita
    Tak třeba v java verzi minecraftu je/bylo tak 90% modů dělaných tím, že se přímo do minecraft.jar souboru překopírovaly .class soubory modu (nové + overwrite) a výsledek zhruba fungoval (ale zda je to normální použití to ale fakt nevím).
    xkucf03 avatar 13.2.2016 12:01 xkucf03 | skóre: 49 | blog: xkucf03
    Rozbalit Rozbalit vše Re: API/ABI kompatibilita

    Ne, to fakt normální není :-) Je to na úrovni crackování binárky, přepisování instrukcí kdesi uvnitř nebo pirátských překladů (opět úprava binárky, kde přeložený výraz musel být stejně dlouhý jako ten původní).

    Pro inspiraci, jak se řeší modularita a rozšiřování funkcí programu, se podívej na Netbeans, Eclipse, jEdit, OSGi, META-INF/services…

    Nové JARy/třídy se přidávají na CLASS_PATH nebo se načítají za běhu programu – nebudeš je přibalovat do původního JARu, natož abys v něm něco přepisoval.

    Mám rád, když se lidé přou, znamená to, že vědí, co dělají, a že mají směr. Frantovo.cz, SQL-DK, Relational pipes
    13.2.2016 11:00 smazáno | skóre: 18 | blog: smazáno
    Rozbalit Rozbalit vše Re: API/ABI kompatibilita
    Jeste si rikam jak casto rozsireni parent tridy zpusobi takoveto problemy, ale debugovat bych to nechtel :).
    xkucf03 avatar 13.2.2016 12:15 xkucf03 | skóre: 49 | blog: xkucf03
    Rozbalit Rozbalit vše Verzování tříd a dědičnost

    Pokud ti hodně záleží na kompatibilitě a zároveň chceš umožnit dědění tříd, které tvoří veřejné API, tak můžeš použít verzování tříd.

    Znamená to, že třídu, kterou jednou vydáš jako součást veřejného API nesmíš už nikdy měnit – resp. nesmíš měnit hlavičky jejích metod nebo zásadním významem jejich vnitřek (např. metoda bude vracet pořád boolean a na vstupu bude mít pořád intString, ale v nové verzi bude vracet negaci a význam parametrů bude jiný – to je samozřejmě špatně, ale to bys neměl dělat bez ohledu na dědičnost).

    Pokud ji chceš rozšířit, vytvoříš třídu Třída2, Třída3, Třída4…, které se postupně dědí. Náročné je to v tom, že v kódu, který má používat novou funkcionalitu musíš mít výhybky, ověřovat instanceof TřídaX a přetypovávat + se nějak vyrovnat s případem, kdy nová funkcionalita chybí (dostal jsi jen instanci předka).

    Ten, kdo chce podědit třídu z veřejného API, podědí konkrétní verzi třídy (do které mu už nikdo nic dalšího nepřidá, takže ke kolizi nemůže dojít). Ale na druhou stranu nemůžeš automaticky profitovat z nových funkcí – musíš upravit svůj kód potomka a přepsat tam třeba Třída2Třída3 a vydat novou verzi potomka.

    Mám rád, když se lidé přou, znamená to, že vědí, co dělají, a že mají směr. Frantovo.cz, SQL-DK, Relational pipes
    pavlix avatar 13.2.2016 13:59 pavlix | skóre: 54 | blog: pavlix
    Rozbalit Rozbalit vše Re: API/ABI kompatibilita
    Od napsání blogpostu už se mi to jednou stalo. :)
    Já už tu vlastně ani nejsem. Abclinuxu umřelo.
    13.2.2016 13:37 Ondrej Santiago Zajicek
    Rozbalit Rozbalit vše Re: API/ABI kompatibilita
    Ale co když člověk používá dědičnost? Tam přece jakékoli přidání funkce vede na potenciální kolizi s odvozenou třídou.
    IMHO tohle je problem, ktery nesouvisi ani tak s OOP jako spis s namespace managementem daneho jazyka.

    C nema namespaces, ktere by staly za zminku, proto v nem vsichni pouzivaji explicitni prefixy. Jmeno s prefixem tedy defacto slouzi jako absolutni identifikator a kolize jmen z ruznych namespaces tedy nenastavaji. Pokud ale mas jazyk s namespaces a pouzijes nejake (relativni) jmeno v kontextu, kde je mozne ho resolvovat ve dvou ruznych namespaces s tim, ze se nachazi jenom v jednom, tak mas do boudoucna problem.

    Jak to souvisi s OOP? Tridy je mozne chapat jako (vnorene) namespaces. Pouziti metody objektu tedy znamena, ze jmeno jmeno je treba resolvovat v hierarchii namespaces prislusnych trid. Pokud by se vzdy pouzivala absolutni jmena (a la C), tak ke kolizi nedojde. Napr. mame tridu xxx a jejiho potomka yyy. Pokud do yyy pridam metodu yyy_print(). tak nemuze dojit ke kolizi s pripadnym pozdejsim pridanim metody do xxx. Pokud bych ale v yyy chtel cilene prekryt metodu tridy xxx, tak pro ni pouziju jmeno xxx_print().

    Ale je pravda, ze vzdy pouzivat absolutni jmena je dost otravne. Tohle je problem, nad kterym jsem uz kdysi premyslel, a napadlo me akorat: Pred kompilaci programu vlozit fazi, ktera provede strojove resolvovani jmen (tedy pro kazdy kontext a relativni jmeno se nalezne absolutni jmeno) a tuto informaci ulozi explicitne vedle zdrojaku. Pripadne muze hlasit kolize, ktere musi vyvojar vyresit. Pri jakekoliv pozdejsi kompilaci (napr. u uzivatele) uz jsou tedy absolutni jmena znama a ke kolizim dojit nemuze. Vysledek teto faze je mozne znovupouzit i pri pozdejsim behu teto faze (napr. po uprave zdrojaku) a automaticky tak vyresit kolize, ktere se od minula objevily (napr. proto, ze nove verze knihoven exportuji nove symboly).

    Alternativou by bylo by pri importu namespaces z knihoven vzdy explicitne uvadet pozadovanou verzi s tim, ze knihovna by u kazdeho jmena mela informaci, v ktere verzi se objevilo. To je svym zpusobem vyrazne jednodussi nez predchozi pristup, ale nefungoval by v situaci, kdy by knihovna mela nelinearni vyvoj (napr. v dusledku forku).
    pavlix avatar 13.2.2016 14:10 pavlix | skóre: 54 | blog: pavlix
    Rozbalit Rozbalit vše Re: API/ABI kompatibilita
    A jak do toho zapadá ten nápad s vyžadováním @Overrides? To by znamenalo, že se metoda odvozené třídy použije jenom v kódu psaném pro odvozenou třídu a nikoli v kódu psaném pro upravenou původní třídu. V zásadě by to znamenalo, že by člověk klidně mohl mít v hierarchii dvě virtuální metody stejného jména a jen od třídy, která by metodu znovu definovala, dále by se používala ta nová.
    Já už tu vlastně ani nejsem. Abclinuxu umřelo.
    13.2.2016 14:33 Ondrej Santiago Zajicek
    Rozbalit Rozbalit vše Re: API/ABI kompatibilita
    A jak do toho zapadá ten nápad s vyžadováním @Overrides?
    Nic jako @Overrides by nebylo treba. Pokud by autor potomka chtel cilene pretizit virtualni metodu, musel by se v definici explicitne odkazat ve jmene na predka, ktery danou virtualni metodu zavedl.
    To by znamenalo, že se metoda odvozené třídy použije jenom v kódu psaném pro odvozenou třídu a nikoli v kódu psaném pro upravenou původní třídu.
    Nova metoda se pouzuje jen takto. Pretizena virtualni metoda se pouzije i vsude v kode pro puvodni tridu.
    V zásadě by to znamenalo, že by člověk klidně mohl mít v hierarchii dvě virtuální metody stejného jména
    Ano. To je proste rozdil mezi slovy a koncepty. Pokud definuji nesouvisejici metodu/funkci/tridu a dam ji stejne jmeno, ktere koliduje s jiz existujici, tak to je analogicke k situaci homonym v prirozenem jazyce. Uzivatel akorat musi vedet, o co jde, a mit moznost explicitne vybrat, na ktery koncept odkazuje.
    jen od třídy, která by metodu znovu definovala, dále by se používala ta nová.

    Samozrejme i tam by bylo mozne pouzit tu puvodni tim, ze se pri odkazu pouzije identifikace prislusneho namespace.
    pavlix avatar 13.2.2016 14:55 pavlix | skóre: 54 | blog: pavlix
    Rozbalit Rozbalit vše Re: API/ABI kompatibilita
    Nic jako @Overrides by nebylo treba. Pokud by autor potomka chtel cilene pretizit virtualni metodu, musel by se v definici explicitne odkazat ve jmene na predka, ktery danou virtualni metodu zavedl.

    Spíše mě zajímo @Overrides bez explicitního odkazování.
    Uzivatel akorat musi vedet, o co jde, a mit moznost explicitne vybrat, na ktery koncept odkazuje.
    To by v tomto případě typicky nebyl problém. Pokud by se jednalo jen o aplikaci a knihovnu, tak je zjevné, že aplikace metodu nadřazené třídy nezná. Ve chvíli, kdy je potřeba, aby ji znala, stačí kolidující metodu v aplikaci přejmenovat.

    Jiná věc je dědičnost od knihovny ke knihovně a od té k aplikaci. Tam by samozřejmě mohlo mít smysl z aplikace specifikovat, že mě zajímá metoda nepřímo používané knihovny namísto přirozeně dostupné metody přímo používané knihovny.
    Samozrejme i tam by bylo mozne pouzit tu puvodni tim, ze se pri odkazu pouzije identifikace prislusneho namespace.
    Jasně. V tom výjimečném případě, kdy je to potřeba.
    Já už tu vlastně ani nejsem. Abclinuxu umřelo.
    xkucf03 avatar 13.2.2016 15:05 xkucf03 | skóre: 49 | blog: xkucf03
    Rozbalit Rozbalit vše Re: API/ABI kompatibilita
    Ta anotace se jmenuje @Override nikoli @Overrides.
    Mám rád, když se lidé přou, znamená to, že vědí, co dělají, a že mají směr. Frantovo.cz, SQL-DK, Relational pipes
    xkucf03 avatar 13.2.2016 15:12 xkucf03 | skóre: 49 | blog: xkucf03
    Rozbalit Rozbalit vše Volání metody původního předka zvenku? Raději ne.
    Jiná věc je dědičnost od knihovny ke knihovně a od té k aplikaci. Tam by samozřejmě mohlo mít smysl z aplikace specifikovat, že mě zajímá metoda nepřímo používané knihovny namísto přirozeně dostupné metody přímo používané knihovny.

    Tohle už je takový šamanismus a alchymie – potenciálně dost nebezpečné a nevyzpytatelné. Když někdo překryl určité metody a dal obecně třídě trochu jiné chování, měl k tomu nějaký důvod, a takhle poděděné by to mělo dávat nějaký smysl a být konzistentní. Když ale zvenku ten jeho kód obejdeš a pokoutně zavoláš metodu předka, tak to může vést na dost podivné chování, nekonzistentní a nevyzpytatelné výsledky.

    Mám rád, když se lidé přou, znamená to, že vědí, co dělají, a že mají směr. Frantovo.cz, SQL-DK, Relational pipes
    pavlix avatar 13.2.2016 15:20 pavlix | skóre: 54 | blog: pavlix
    Rozbalit Rozbalit vše Re: Volání metody původního předka zvenku? Raději ne.
    Volání nepřímo zděděné metody považuješ za obcházení?
    Já už tu vlastně ani nejsem. Abclinuxu umřelo.
    xkucf03 avatar 13.2.2016 15:46 xkucf03 | skóre: 49 | blog: xkucf03
    Rozbalit Rozbalit vše Re: Volání metody původního předka zvenku? Raději ne.

    Pokud je to zvenku1, tak ano. Autor potomka měl nějakou koncepci, nějaké důvody, proč překryl určité metody… a takhle dohromady ta třída potomka dává smysl, je konzistentní. Ale kdybys zvenku ten jeho kód přeskočil a chtěl volat přímo kód předka, tak se to může chovat chybně, nevyzpytatelně. To raději použij kompozici než dědičnost.

    [1] z potomka tu možnost samozřejmě máš, slouží k tomu klíčové slovo super: @Override public String getX() { return super.getX(); }

    Mám rád, když se lidé přou, znamená to, že vědí, co dělají, a že mají směr. Frantovo.cz, SQL-DK, Relational pipes
    pavlix avatar 13.2.2016 16:17 pavlix | skóre: 54 | blog: pavlix
    Rozbalit Rozbalit vše Re: Volání metody původního předka zvenku? Raději ne.
    Bavíme se zde o volání metody, kterou autor potomka nepřekryl. Otázka je, zda jsi vůbec pochopil, o čem se tady s Ondrou bavíme.
    Já už tu vlastně ani nejsem. Abclinuxu umřelo.
    13.2.2016 15:25 Ondrej Santiago Zajicek
    Rozbalit Rozbalit vše Re: Volání metody původního předka zvenku? Raději ne.
    Tohle už je takový šamanismus a alchymie – potenciálně dost nebezpečné a nevyzpytatelné. Když někdo překryl určité metody a dal obecně třídě trochu jiné chování, měl k tomu nějaký důvod, a takhle poděděné by to mělo dávat nějaký smysl a být konzistentní.

    Myslim, ze nerozlisujes dva pripady, ktere diskutujeme - pretizeni virtualni metody vs. zalozeni nove virtualni metody se stejnym jmenem. Zatimco u toho prvniho by se vzdy mela volat pretizena metoda, zatimco u toho druheho pripadu se jedna o rovnocenne moznosti (a stejne jmeno maji dost mozna jen nahodne) a volat puvodni virtualni metodu je zcela korektni. Pokud by autor potomka to tak nechtel, tak by explicitne pretizil metodu predka misto vytvareni nove.
    pavlix avatar 13.2.2016 15:34 pavlix | skóre: 54 | blog: pavlix
    Rozbalit Rozbalit vše Re: Volání metody původního předka zvenku? Raději ne.
    Pokud by autor potomka to tak nechtel, tak by explicitne pretizil metodu predka misto vytvareni nove.
    Přesně tak. Navíc toto autor nedělá vědomě. Může buď přehlédnout, že metoda toho jména existuje, nebo hůře, může se metoda na předkovi objevit dodatečně při aktualizaci knihovny.
    Já už tu vlastně ani nejsem. Abclinuxu umřelo.
    xkucf03 avatar 13.2.2016 15:49 xkucf03 | skóre: 49 | blog: xkucf03
    Rozbalit Rozbalit vše Re: Volání metody původního předka zvenku? Raději ne.

    Pokud se nejedná o překrytí, ale o dvě různé metody1, tak ano – volání metody původního předka je samozřejmě legitimní, nic proti tomu.

    (jen pro zajímavost: funguje to takhle někde?)

    [1] které se vlastně ani nejmenují stejně, protože každá je v nějakém jiném „jmenném prostoru“

    Mám rád, když se lidé přou, znamená to, že vědí, co dělají, a že mají směr. Frantovo.cz, SQL-DK, Relational pipes
    13.2.2016 16:07 Ondrej Santiago Zajicek
    Rozbalit Rozbalit vše Re: Volání metody původního předka zvenku? Raději ne.
    (jen pro zajímavost: funguje to takhle někde?)
    Znam takove objektove modely ze LISPu/Scheme. Tam jsou namespace zcela oddeleny od trid. Jmena odkazuji na 'genericke funkce' a jednotlive tridy pridavaji sve 'virtualni metody' do dane 'generickych funkci'. Pokud chces pretizit metodu, tak pridas metodu do existujici genericke funkce, zatimco pokud definujes uplne novou, tak zridis i novou generickou funkci. Namespace se postara o (lexikalni) vyber genericke funkce, Genericka funkce sama se postara o (dynamicky) typovy dispatch.
    pavlix avatar 13.2.2016 16:27 pavlix | skóre: 54 | blog: pavlix
    Rozbalit Rozbalit vše Re: Volání metody původního předka zvenku? Raději ne.
    To zní zajímavě, ale takhle si to úplně nepředstavím. Generická funkce v tomto případě nahrazuje pointer v tabulce virtuálních funkcí, jestli to dobře chápu.
    Já už tu vlastně ani nejsem. Abclinuxu umřelo.
    13.2.2016 16:38 Ondrej Santiago Zajicek
    Rozbalit Rozbalit vše Re: Volání metody původního předka zvenku? Raději ne.
    Ano, i kdyz spis to nahrazuje funkci, ktera ten pointer vezme a zavola ho misto sebe.

    V tech systemech ale typicky funguje dynamicky dispatch podle typu vsech argumentu, takze namisto toho, aby trida/objekt mel(a) tabulku virtualnich funkci, tak genericka funkce ma seznam metod, pri zavolani sebe ho prochazi, matchuje typy argumentu a zavola tu metodu, ktera nejlepe matchuje vzhledem k aktualnim typum argumentu.
    13.2.2016 15:15 Ondrej Santiago Zajicek
    Rozbalit Rozbalit vše Re: API/ABI kompatibilita
    To by v tomto případě typicky nebyl problém. Pokud by se jednalo jen o aplikaci a knihovnu, tak je zjevné, že aplikace metodu nadřazené třídy nezná. Ve chvíli, kdy je potřeba, aby ji znala, stačí kolidující metodu v aplikaci přejmenovat.
    Ano, z hlediska citelnosti a prehlednosti je urcite lepsi se kolidujicim jmenum vyhnout. Z hlediska korektnosti a zpetne/dopredne kompatibility je dobre ten jazyk navrhnout tak, ze by i pri kolizich dobre fungoval. Akorat by to pri necekanych kolizich mohlo napr. vypisovat warningy pri kompilaci.
    Jiná věc je dědičnost od knihovny ke knihovně a od té k aplikaci. Tam by samozřejmě mohlo mít smysl z aplikace specifikovat, že mě zajímá metoda nepřímo používané knihovny namísto přirozeně dostupné metody přímo používané knihovny.
    Tady bych zminil, ze ten postup zminovany v mem prvnim postu (predposledni odstavec) resi jak pripad, kdy danou metodu nejdrive pridala knihovna potomka a az v budoucnosti knihovna predka, tak pripad opacny. V obou pripadech by se (na zaklade ulozenych vysledku o resolvovani) pri pozdejsi kompilaci pouzilo 'spravna' metoda (ta, ktera existovala v dobe puvodniho resolvovani jmen).
    pavlix avatar 13.2.2016 15:39 pavlix | skóre: 54 | blog: pavlix
    Rozbalit Rozbalit vše Re: API/ABI kompatibilita
    Tady bych zminil, ze ten postup zminovany v mem prvnim postu (predposledni odstavec) resi jak pripad, kdy danou metodu nejdrive pridala knihovna potomka a az v budoucnosti knihovna predka, tak pripad opacny. V obou pripadech by se (na zaklade ulozenych vysledku o resolvovani) pri pozdejsi kompilaci pouzilo 'spravna' metoda (ta, ktera existovala v dobe puvodniho resolvovani jmen).
    Už rozumím. Ale osobně generovaná data nepovažuju za součást zdrojových kódů. Takže pokud bych udržoval jen skutečné zdrojové kódy, tak bys zřejmě docílil ABI kompatibility, ale API kompatibilita by byla omezena nutností dospecifikovat třídu u volání kolidujícího jména.
    Já už tu vlastně ani nejsem. Abclinuxu umřelo.
    13.2.2016 15:53 Ondrej Santiago Zajicek
    Rozbalit Rozbalit vše Re: API/ABI kompatibilita
    Tato generovana data by byla soucasti distribuovanych zdrojovych kodu v ramci release. Proto to taky chapu jako fazi explicitne oddelenou od kompilace.
    pavlix avatar 13.2.2016 22:47 pavlix | skóre: 54 | blog: pavlix
    Rozbalit Rozbalit vše Re: API/ABI kompatibilita
    Jo, já jsem se to pochopil. Jen se snažím takovým věcem vyhnout a pokud možno nedávat do gitu žádná generovaná data.
    Já už tu vlastně ani nejsem. Abclinuxu umřelo.
    xkucf03 avatar 13.2.2016 15:02 xkucf03 | skóre: 49 | blog: xkucf03
    Rozbalit Rozbalit vše Re: API/ABI kompatibilita
    Nic jako @Override by nebylo treba. Pokud by autor potomka chtel cilene pretizit virtualni metodu, musel by se v definici explicitne odkazat ve jmene na predka, ktery danou virtualni metodu zavedl.

    Co když tam bude posloupnost dědění A ← B ← C? Původně bude metoda jen v A a já ji podědím v C. V další verzi ale podědí tuhle metodu i B a já budu muset přepisovat C.

    Každý z těch přístupů má svoje, chápu, že ten tvůj je teoreticky bezpečnější, ale přijde mi možná až moc paranoidní. Skutečně je potřeba rozlišovat, jestli překrývám metodu přímého předka nebo nepřímého?

    Osobně bych dal přednost @Override anotaci vynucené kompilátorem, kde stačí říct, že překrývám metodu předka, ale už nemusím říkat, kterého.

    (kartami zamíchá až vícenásobná dědičnost – chceme-li ji podporovat – tam už bych považoval za nutné deklarovat, kterého předka metodu překrývám)

    Mám rád, když se lidé přou, znamená to, že vědí, co dělají, a že mají směr. Frantovo.cz, SQL-DK, Relational pipes
    pavlix avatar 13.2.2016 15:24 pavlix | skóre: 54 | blog: pavlix
    Rozbalit Rozbalit vše Re: API/ABI kompatibilita
    Co když tam bude posloupnost dědění A ← B ← C? Původně bude metoda jen v A a já ji podědím v C. V další verzi ale podědí tuhle metodu i B a já budu muset přepisovat C.
    Pokud je metoda v A a jiné třídy ji pouze podědí, pak přece žádná kolize nenastává. Bavíme se tady o případu, kdy se metody shodují v názvu a přitom jedna není specializací druhé.
    Já už tu vlastně ani nejsem. Abclinuxu umřelo.
    13.2.2016 15:34 Ondrej Santiago Zajicek
    Rozbalit Rozbalit vše Re: API/ABI kompatibilita
    Co když tam bude posloupnost dědění A ← B ← C? Původně bude metoda jen v A a já ji podědím v C. V další verzi ale podědí tuhle metodu i B a já budu muset přepisovat C.
    Pokud C pretizi metodu definovanou z A, tak se bude odkazovat na A. To, zda ji pretizi ci nepretizi i B, na veci nic nemeni.
    xkucf03 avatar 13.2.2016 16:02 xkucf03 | skóre: 49 | blog: xkucf03
    Rozbalit Rozbalit vše Re: API/ABI kompatibilita
    To, zda ji pretizi ci nepretizi i B, na veci nic nemeni.

    A co by potom dělal následující kód?

    public void něcoDělej(B b) {
        b.první();
        b.druhá();
    }

    Tento kód někdo zavolá a jako parametr předá instanci třídy C. Metoda první() je jen v A, tam je to jednoduché.

    Ale metoda druhá() je v AC. Jak se to bude chovat?

    A jak se to bude chovat po úpravě kódu třídy B, kdy metoda druhá() bude v A, BC, ale C se nezmění, bude stále deklarovat, že překrývá metodu A? (něcoDělej() deklaruje stále parametr typu B, ale reálně dostává instanci C, to se nemění)

    Obávám se, že spolehlivé a bezpečné řešení by vyžadovalo jiný způsob zápisu volání metod, který by byl mnohem méně přehledný.

    Mám rád, když se lidé přou, znamená to, že vědí, co dělají, a že mají směr. Frantovo.cz, SQL-DK, Relational pipes
    13.2.2016 16:31 Ondrej Santiago Zajicek
    Rozbalit Rozbalit vše Re: API/ABI kompatibilita
    Ale metoda druhá() je v A a C. Jak se to bude chovat?
    Pokud je metoda druhá() definovana v C jako pretizeni metody z A, tak se zavola druhá() z C (predpokladame-li dynamickou vazbu). Pokud je metoda druhá() definovana v C nezavisle, tak se zavolá druhá() z A.
    A jak se to bude chovat po úpravě kódu třídy B, kdy metoda druhá() bude v A, B i C, ale C se nezmění, bude stále deklarovat, že překrývá metodu A?
    Tak se stale zavolá druhá() z C. Tedy v pripade, ze by metoda druhá() v B byla take definovana jako pretizeni te z A.

    Zajimave by to bylo v situaci, kdy by B namisto toho definovala metodu druhá() nezavisle. Pak by preklad po uprave kodu zavisel na ulozenych informacich o resolvovanych symbolech. Pokud by něcoDělej() vznikla pred tim, nez se pridala druhá() do B (a tedy by bylo poznamenano ze druhá() v tomto kontextu se resolvuje na virtualni metodu z A nebo jeji pretizeni). Pak by se nejden zavolala druhá() z C pro instanci tridy C, ale dokonce by se zavolala druhá() z A pro instanci tridy B. Pokud by něcoDělej() vznikla pozdeji (nebo by programator explicitne smazal ulozene vysledky resolvovani), tak by se to chapalo jako volani druhá() z B jak pro instanci tridy B, tak pro instanci tridy C. V obou pripadech z tohoto odstavce by to vypisovalo warning o kolizi metody druhá() mezi A a B.
    13.2.2016 15:49 Ondrej Santiago Zajicek
    Rozbalit Rozbalit vše Re: API/ABI kompatibilita
    Pavlix: Spíše mě zajímo @Overrides bez explicitního odkazování.
    xkucf03: kde stačí říct, že překrývám metodu předka, ale už nemusím říkat, kterého
    Ono v tom mem pristupu vlastne neni nutne explicitne odkazovat na predka. Staci rozlisit, zda se zaklada nova metoda, nebo pretezuje predchozi. Resolvovani pro nalezeni absolutniho identifikatoru dane metody (v pripade 'pretizeni') se zvladne v ramci kompilace kodu knihovny potomka.
    xkucf03 avatar 13.2.2016 14:05 xkucf03 | skóre: 49 | blog: xkucf03
    Rozbalit Rozbalit vše Modularita a kolize jmen při dědičnosti – OSGi a sémantické verzování

    Jinak řešením toho problému s kolizí jmen a nechtěným překrytím metody, která později přibyla v předkovi, je používat sémantické verzování a nějaký modulární framework např. OSGi.

    Ve svém kódu, který dědí, deklaruješ závislost na knihovně předka např. 1.1.x a OSGi zajistí, že se ti načte správná verze. Při změně patch verze se opravují chyby, ale nesmí přibývat nová funkcionalita – na úrovni tříd (tvořících veřejné API) tedy nemůže přibýt nová metoda. Pokud by metoda přibyla, musela by se zvýšit minor verze, tzn. byla by to knihovna 1.2.0 a s tou jsi nedeklaroval kompatibilitu, takže se nepoužije.

    Jestliže nepoužíváš dědičnost, tak můžeš deklarovat kompatibilitu jako větší nebo rovno 1.1.0 a menší než 2.0.0 a bude ti to fungovat, protože dodatečné metody a funkcionalita ti nevadí – stačí, že to umí vše, co uměla verze 1.1.0, což platí.

    OSGi je jen příklad – stačí se podívat do /usr/share/java – jsou tam různé verze různých knihoven instalované vedle sebe – program by si pak měl vybrat tu správnou, se kterou je kompatibilní.

    Stejný princip jde aplikovat i na jiné jazyky (pokud s tím není vyloženě technický problém jako u toho C++). Některé distribuce jako GuixSD tomu přímo nahrávají (umožňují instalovat více verzí stejného balíku).

    Mám rád, když se lidé přou, znamená to, že vědí, co dělají, a že mají směr. Frantovo.cz, SQL-DK, Relational pipes
    13.2.2016 14:15 Jardík
    Rozbalit Rozbalit vše Re: API/ABI kompatibilita
    C++ je z hlediska ABI kompatibility hrozná věc. Koukněte, jak se to musí řešit, buď uděláte abstraktní třídu, a pak uděláte factory metodu a dáte uživateli objekt, jenže ... virtuální metody představují overhead. Někdy nevadí, někdy jo. Pak se to může řešit nějakým pimplem, což je hrozná prasárna, kdy uživateli tvrdíte "tento objekt může být alokován na zásobníku a může z něho být děděno", ale už mu neřeknete "ale hele vole, mám tu alokaci ha heapu, tak mě taky nealokuj na heapu, jinak máš další zbytečnou alokaci. Spousta pimplů. A pak ještě overhead delegace metody na pimpl, pokud se zrovna kompilátoru nebude chtít inlinovat (třeba dlouhá fce bude volána více než jednou, tak jí nebude inlinovat). No a řešení bez overheadu je těžkopádné, takový hybrid mezi oběma.
    class MojeTrida
    {
      static MojeTrida* debilni_factory();
      virtual ~MojeTrida();
    
      void delej_neco();
    protected:
      MojeTrida();
    };
    
    struct MojeTajnaImplementace : public MojeTrida
    {
      int sracka1, sracka2;
    };
    
    void MojeTrida::delej_neco()
    {
      static_cast<MojeTajnaImplementace*>(this)->sracka1 = 20;
    }
    
    Ve výsledku, všechny řešení jsou sračky a zůstaneme u C. Já jsem nějak C++ přestal mít rád. Nutí mě do veřejného API očkovat tuny hlavičkových souborů, co tam musí být jen kvůli interní implementaci, to pak prodlužuje nechutně kompilaci. Radši si těch pár písmenek na víc napíšu.
    pavlix avatar 13.2.2016 14:33 pavlix | skóre: 54 | blog: pavlix
    Rozbalit Rozbalit vše Re: API/ABI kompatibilita
    Ten overhead je zrovna v C++ minimální a navíc máš možnost používat i nevirtuální metody.
    Já už tu vlastně ani nejsem. Abclinuxu umřelo.
    13.2.2016 19:21 Jardík
    Rozbalit Rozbalit vše Re: API/ABI kompatibilita
    Jo však ta ukázka je nepoužívá (kromě destruktoru, který je potřeba, pokud nemáš ty factory metodu na uvolnění či speciální smart pointer). Používá static_cast a jeho overhead bude v v případě jednoduché dědičnosti nulový, protože pointer je shodný a žádný offset se neděje. U standardního pimplu však můžete dostat extra call, tj. prakticky se nevyplatí upustit od virtuálních metod, pokud zároveň nechcete dědit a využít původní implementaci. A protože je cílem implementaci skrýt, tak právě proto ani nechci dovolit dědit. Overhead je 'minimální' v obou případech, pokud dané fce nejsou volány často a třeba i ve smyčce, nebo při paměťově náročných operacích, kde se počítá každý cache miss.
    13.2.2016 19:09 Tomáš
    Rozbalit Rozbalit vše Re: API/ABI kompatibilita
    Pokud vím, tak Python nemá přetěžování metod jako C++ (stejný název metody, různé parametry), takže při přidání metody, která ještě neexistuje (ať už v aktuálním objektu nebo předkovi) nehrozí kolize. Ale v Pythonu je těch metodu na předkovi definováno docela dost (většinou typu __název__).

    Jiná situace je v C++, C#, Java apod. Tam se může stát, že si přetížíš metodu a v kombinaci s implicitními parametry a trochou smůly je dílo zkázy na světě. Kód, který dřív volal starou metodu, bude volat tu novou. Pokud si před vydáním neprojedeš testy, dílo zkázy je dokonáno.
    13.2.2016 19:34 Jardík
    Rozbalit Rozbalit vše Re: API/ABI kompatibilita
    Imho C# má na tohle nástroj. Když tvá třída implementuje interface a několik z nich má metodu se stejným názvem, tak v tvé třídě můžeš explicitně definovat, z jakého interfacu ji implementiješ:
    interface A {
      void a();
    }
    
    interface B {
      void a();
    }
    
    class C : A, B {
      void A.a() {}
      void B.b() {}
    }
    
    V C# teda neprogramuji, ale tohle se mi na něm líbí, co by bylo hezké i v jiných jazycích, třeb java, C++ a D. Velmi se to hodí, když narazíte na nutnosti.

    V Javě 8 přistálo něco jako default metody v interfacu. To je taky vskutku nebezpečná věc, protože přidávají nové metody do interfacu s nějakou výchozí implementací, a pokud metodu s takovým jménem zrovna máte ve vaší třídě, je problém.

    Jinak proč se mi poslední doubou nelíbí C++, od C++11 se do standardní knihovny dostává příliš 'bloatu'. Za vlákna jsem třeba rád, ale za nedomyšlené async() a nedomyšlený std::future, nebo zbytečně přeplácané a složité std::chrono. A hlavičkové soubory toho tahají čím dál víc jako svoje 'závislosti' a lezou vám do vaší veřejné implementace. A nedej Bože, když to zkombinujete s boostem, to je pak utrpení, hlavně když v současné době C++11/14 obsahuje duplicitu půlku z toho.
    xkucf03 avatar 13.2.2016 19:47 xkucf03 | skóre: 49 | blog: xkucf03
    Rozbalit Rozbalit vše Výchozí metody v Javě 8
    V Javě 8 přistálo něco jako default metody v interfacu. To je taky vskutku nebezpečná věc, protože přidávají nové metody do interfacu s nějakou výchozí implementací, a pokud metodu s takovým jménem zrovna máte ve vaší třídě, je problém.

    Ono to taky není určené k programování stylem: „mám nějakou třídu, která dělá kde co, a teď k ní přidám ještě tohle rozhraní… a budu se divit“ – smysluplné a zamýšlené využití je v tom, že vytvoříš jednoúčelovou třídu (typicky jako lambda výraz) implementující právě to jedno rozhraní. Výchozí metoda definovaná v rozhraní pak slouží k tomu, že nějak obaluje/vylepšuje funkcionalitu, kterou poskytuješ v tom lambda výrazu – výsledkem je elegantní a úsporný kód.

    Mám rád, když se lidé přou, znamená to, že vědí, co dělají, a že mají směr. Frantovo.cz, SQL-DK, Relational pipes
    14.2.2016 10:13 x
    Rozbalit Rozbalit vše Re: API/ABI kompatibilita
    V Javě 8 přistálo něco jako default metody v interfacu. To je taky vskutku nebezpečná věc, protože přidávají nové metody do interfacu s nějakou výchozí implementací, a pokud metodu s takovým jménem zrovna máte ve vaší třídě, je problém.
    Metoda zděděná ze třídy má vždycky přednost před metodou zděděnou z rozhraní. Takže problém je spíš opačný -- když počítám s tím, že nějakou metodu zdědím z rozhraní, ale zároveň dědím od nějaké třídy a ta v nové verzi přidala metodu stejné signatury jako má to rozhraní.
    pavlix avatar 14.2.2016 10:18 pavlix | skóre: 54 | blog: pavlix
    Rozbalit Rozbalit vše Re: API/ABI kompatibilita
    No vidím, že dobrá pověst Javy značně předchází realitu. Tohle je přece úplně špatně. Zvlášť když interface má být jediný bezpečný způsob, jak API tvořit.
    Já už tu vlastně ani nejsem. Abclinuxu umřelo.
    15.2.2016 19:49 x
    Rozbalit Rozbalit vše Re: API/ABI kompatibilita
    Tenhle problém mají inherentně všechny jazyky s jakoukoli formou vícenásobné dědičnosti (ano, Java má od verze 8 vícenásobnou dědičnost chování, byť ne stavu). IMHO skoro žádný jazyk nepovažuje evoluci API za důležitý návrhový cíl (a to jsou ty defaultní metody v Javě zamýšlené hlavně pro evoluci interfaců!).
    pavlix avatar 15.2.2016 21:48 pavlix | skóre: 54 | blog: pavlix
    Rozbalit Rozbalit vše Re: API/ABI kompatibilita
    Nějak nevím, co si mám z toho komentáře vzít.
    Já už tu vlastně ani nejsem. Abclinuxu umřelo.
    xkucf03 avatar 14.2.2016 11:37 xkucf03 | skóre: 49 | blog: xkucf03
    Rozbalit Rozbalit vše Re: API/ABI kompatibilita

    Proto se ty metody v rozhraní jmenují default – je to jen výchozí implementace, kterou můžeš ve třídě překrýt.

    Pokud máš dobrý návrh, tenhle problém nenastane. Pokud máš špatný návrh, stanou se ti mnohem horší věci.

    Dědičnost je poměrně „intimní“ vztah a nehodí se na všechno. Dědit od cizích tříd, které ti může kdykoli někdo pod rukama změnit, není zrovna optimální.1 Splácat víc věcí do jedné třídy taky není dobrá praktika.

    Co má být vlastně cílem? Nějaký god object, který jednou použiješ v roli jeho předka a jindy v roli instance toho rozhraní? Každá půlka toho objektu dělá zjevně něco jiného2 a není důvod nacpat obě do jedné třídy. Vše nasvědčuje tomu, že se měla použít spíš kompozice než dědičnost.

    [1] možná řešení už tu padla: používat ve veřejném API spíš rozhraní než třídy, používat final třídy, neměnit nečekaně třídy, které někdo dědí, verzovat třídy, používat sémantické verzování modulů, testovat (měl bys mít jednak jednotkové testy k té třídě a jednak integrační/systémové testy celé aplikace)…
    [2] jinak by autor třídy předka počítal s tím, že se používá v souvislosti s tím rozhraním a nepřidával by do ní stejnou metodu, nebo by ji tam naopak přidal záměrně a mělo by to smysl

    Mám rád, když se lidé přou, znamená to, že vědí, co dělají, a že mají směr. Frantovo.cz, SQL-DK, Relational pipes
    pavlix avatar 14.2.2016 13:37 pavlix | skóre: 54 | blog: pavlix
    Rozbalit Rozbalit vše Re: API/ABI kompatibilita
    a jednak integrační/systémové testy celé aplikace)…
    Testování na systému, který umí aktualizovat jednotlivé komponenty, nemusí pomoct. Sice se to obecně řešní doporučením, že systém musí být plně aktualizovaný (což velcí hráči dělají), ale nejsem si jistý, zda to tak v praxi funguje.
    [2] jinak by autor třídy předka počítal s tím, že se používá v souvislosti s tím rozhraním a nepřidával by do ní stejnou metodu
    A rozhraní se rozšiřovat nedají? Pokud ne, viděl bych to jako zásadní omezení, protože pak ze jenom celý problém přenáší na rozhraní, která se rovněž budou muset verzovat.
    Já už tu vlastně ani nejsem. Abclinuxu umřelo.
    pavlix avatar 13.2.2016 19:56 pavlix | skóre: 54 | blog: pavlix
    Rozbalit Rozbalit vše Re: API/ABI kompatibilita
    Pokud vím, tak Python nemá přetěžování metod jako C++ (stejný název metody, různé parametry), takže při přidání metody, která ještě neexistuje (ať už v aktuálním objektu nebo předkovi) nehrozí kolize.
    O přetěžování (overloading) ovšem vůbec nebyla řeč.
    Já už tu vlastně ani nejsem. Abclinuxu umřelo.
    14.2.2016 00:04 Michal Kubeček | skóre: 72 | Luštěnice
    Rozbalit Rozbalit vše Re: API/ABI kompatibilita
    Stejnětak rozšiřitelné datové struktury jdou implementovat triviálně. K zachování API i ABI kompatibility stačí objekty vždy alokovat uvnitř knihovny dynamicky a volajícímu je zpřístupňovat výhradně pomocí funkcí. Uživatel tak vlastně dostává jen identifikátor, který knihovna interně používá jako pointer na objekt v paměti.

    Řešit všechno přes pointery a přístupové funkce (které navíc ani nebudou smět být inline) znamená horší výkon, což někomu vadit nemusí, ale pro mnohé projekty to může být naprosto nepřijatelné. A třeba důsledně nahrazovat všechny vnořené struktury pointery znamená i zvýšené riziko chyb. Takže ano, určitě by se to takhle řešit dalo, ale ani zdaleka to není univerzálně použitelný recept.

    pavlix avatar 14.2.2016 02:54 pavlix | skóre: 54 | blog: pavlix
    Rozbalit Rozbalit vše Re: API/ABI kompatibilita
    To je všechno moc hezké a jistě pravdivé, ale bez konkrétních důvodů a příkladů ten komentář podle mě nepřidává do diskuze žádnou uchopitelnou hodnotu. Stačí se podívat, jak se rozjely diskuze výše, ze kterých vyplynulo pár zajímavých bodů, které třeba nikdo ani nečekal. Takže to asi není ani tak o tom blejsknout se, že všechno vím, ale nic neřeknu, ale o lidech, co se do diskuze zapojí trochu víc.
    Já už tu vlastně ani nejsem. Abclinuxu umřelo.
    14.2.2016 13:16 Michal Kubeček | skóre: 72 | Luštěnice
    Rozbalit Rozbalit vše Re: API/ABI kompatibilita
    Jak už je v poslední době nedobrým zvykem, opět nechápu, o co ti vlastně jde. Ani v nejmenším mi nešlo o to "se blejsknout", ale čistě o upozornění, že to jednoduché řešení sice je jednoduché, ale zdaleka ne vždy je vhodné nebo praktické. Jestli to pro tebe bez detailní analýzy a návrhu geniálního řešení, které tímto problémem netrpí, není dost hodnotné, pak se hluboce omlouvám, ale příště bys měl předem upozornit, že do diskuse patří jen příspěvky, které shledáš dostatečně přínosnými, abych věděl, že nemám obtěžovat.
    pavlix avatar 15.2.2016 21:51 pavlix | skóre: 54 | blog: pavlix
    Rozbalit Rozbalit vše Re: API/ABI kompatibilita
    Jak už je v poslední době nedobrým zvykem, opět nechápu, o co ti vlastně jde.
    Popravdě si nepamatuju dobu, kdy by tomu bylo jinak. Diskuze je otevřená, přispívej dle svého uvážení a smiř se s tím, že dělám totéž.
    Já už tu vlastně ani nejsem. Abclinuxu umřelo.
    14.2.2016 19:23 backinabag | blog: backinabag
    Rozbalit Rozbalit vše Re: API/ABI kompatibilita
    Nevim jak v jinych jazycich, ale v Effective Java se doporucuje metody viditelne zvnejsku davat jako defaultne jako final a povolovat (+ dokumentovat) dedicnost individualne. Takze minimalne v Jave resitelny problem.

    Taky nektery lidi zastavaj nazor ze dedicnost by se nemela pouzivat vubec.
    14.2.2016 20:22 Radek Miček | skóre: 23 | blog: radekm_blog
    Rozbalit Rozbalit vše Re: API/ABI kompatibilita
    Taky nektery lidi zastavaj nazor ze dedicnost by se nemela pouzivat vubec.
    Jenže v Javě bez dědičnosti neuděláte podtyp třídy - je to svázané.
    14.2.2016 21:16 backinabag | blog: backinabag
    Rozbalit Rozbalit vše Re: API/ABI kompatibilita
    No prave ze existuje nazor ze podtypy trid by se vubec nemely delat, ze by se mely jenom implementovat interfacy.

    U existujiciho kodu ale samozrejme vetsinou neni na vyber.
    16.2.2016 20:34 Radek Miček | skóre: 23 | blog: radekm_blog
    Rozbalit Rozbalit vše Re: API/ABI kompatibilita
    No prave ze existuje nazor ze podtypy trid by se vubec nemely delat
    To je ale obecně něco jiného než dědičnost.
    17.2.2016 13:08 Ivan
    Rozbalit Rozbalit vše Re: API/ABI kompatibilita
    Dalsi moznosti jak to "resit", je postavit celou situaci tak aby se to vubec resit nemuselo. V C++ existuji header-only knihovny, takze odpadaji problemy s ABI. V Java svete "enterprise" aplikaci se casto setkate s tim, ze jsou ke zrojakum pribaleny konkretni jar-ka, se kteryma jde aplikace zkompilovat. Vendorovi staci rict "Nase aplikace je certifikovana v JKD 1.3, JAXB 1.0.2, JGL 3.0" a tim je to poreseny. A kdyz zacnou programatori prskat, ze se s tim uz neda delat, tak jen posunete support dale na vychod.

    Kolem sebe spis vidim pristup ze se jednou za cas aplikace kompletne prepise, nez aby nekdo resil problemy v verzemi knihoven. O dlouhodobou udrzbu SW nema nikdo zajem. U SW kde je vyvoj mnohem levnejsi nez testovani maji vsichni strach z regresi se takovy veci proste neresi.

    pavlix avatar 17.2.2016 14:20 pavlix | skóre: 54 | blog: pavlix
    Rozbalit Rozbalit vše Re: API/ABI kompatibilita
    Dalsi moznosti jak to "resit", je postavit celou situaci tak aby se to vubec resit nemuselo.
    Tak já se bavil v kontextu komponentového systému jako je třeba Fedora, kde se komponenty běžně samostatně aktualizují.
    V C++ existuji header-only knihovny,
    To je po binární stránce ekvivalent bundlingu a tudíž z tohoto pohledu naprosto zbytečná věc. Stejně dobře můžeš dynamické knihovny bundlovat nebo buildovat staticky.
    Nase aplikace je certifikovana v JKD 1.3, JAXB 1.0.2, JGL 3.0" a tim je to poreseny.
    Tak pokud ke všemu vychází bezpečnostní aktualizace oddělené od funkčních updatů, tak bez problémů.
    O dlouhodobou udrzbu SW nema nikdo zajem.
    Tak já to mám jako primární task v práci. Takže jestli o to nikdo nemá zájem, tak by mě měli každou chvíli vyhodit. :)
    Já už tu vlastně ani nejsem. Abclinuxu umřelo.
    17.2.2016 15:18 Ivan
    Rozbalit Rozbalit vše Re: API/ABI kompatibilita
    Tak já se bavil v kontextu komponentového systému jako je třeba Fedora, kde se komponenty běžně samostatně aktualizují.
    V kontextu Linuxu existuje jeste moznost verzovat symboly na urovni .ELF formatu. To ale prakticky nikdo nepouziva, coz je skoda. Kdyby to bylo privetivejsi a kdyby z kompilatoru padaly nejaky metadata, ze kterych by bylo mozne vycist (alespon nektere) zmeny v ABI tak by to urcite pomohlo. Vyvoj se ale ubira jinym smerem.
    pavlix avatar 17.2.2016 16:02 pavlix | skóre: 54 | blog: pavlix
    Rozbalit Rozbalit vše Re: API/ABI kompatibilita
    V kontextu Linuxu existuje jeste moznost verzovat symboly na urovni .ELF formatu.
    O nějakém verzování pořád mluví lidi od glibc. Možná bych se na to měl někdy podívat. Ale otázku to nijak nemění. Verzování v ELF bude nejspíš funkčně dost podobné verzování v názvu, což u funkcí není zase až tak složité. V obou případech člověk tak jako tak musí udržovat starou i novou verzi.
    Já už tu vlastně ani nejsem. Abclinuxu umřelo.
    19.2.2016 13:56 Ivan
    Rozbalit Rozbalit vše Re: API/ABI kompatibilita
    Popravde receno on to asi ani nikdo jiny nepouziva. Ono je to dost kostrbaty a pouziva se to tak, ze mas vice implementaci jedne fce ve stejnym zdrojaku. Takze nemuzez vzit dve branche, zkompilovat je do .o souboru a ty pak sesypat do jedny knihovny, ktera by podporovala dve verze ABI. Ani nejde z kompilatoru dostat informace u kterych struktur se zmenila velikost, polozky, ... V tomhle je javac napred.
    19.2.2016 18:18 Karel Zak
    Rozbalit Rozbalit vše Re: API/ABI kompatibilita
    Ale pouziva se to...
    $ readelf --symbols /usr/lib64/lib* 2> /dev/null | awk -F '@@' '{ print $2 }' | sed 's/_.*//' | sort -u | wc -l
    194
    
    (jsem linej ten prikaz nejak ucesat, zakladni predstavu to myslim dava)

    Založit nové vláknoNahoru

    ISSN 1214-1267   www.czech-server.cz
    © 1999-2015 Nitemedia s. r. o. Všechna práva vyhrazena.