Zobrazit příspěvky

Tato sekce Vám umožňuje zobrazit všechny příspěvky tohoto uživatele. Prosím uvědomte si, že můžete vidět příspěvky pouze z oblastí Vám přístupných.


Příspěvky - Jiří Havel

Stran: 1 ... 20 21 [22]
316
Vývoj / Re:Ideálny programovací jazyk
« kdy: 15. 05. 2019, 21:40:18 »
Je to problém, protože u spousty struktur nedokážete určit ani co je to ta identita, o hodnotě ani nemluvě.
Hodnota není až takový problém.
Každý složený datový typ jde porovnat prvek po prvku. Invarianty na tom nic nezmění, ty jenom vyloučí některé možnosti. Navíc se takovéhle porovnání dá generovat i automaticky.
Co tím může zamíchat je zavedení nějakých tříd ekvivalence (zlomky, floaty). Nejjednodušší způsob, jak je zavést konzistentně je nějaká forma normalizace.
Pokud nějaký objekt nemá jít porovnat hodnotou, tak je to spíš proto, že to má být neprůhledný blackbox, než že by ani interně žádnou hodnotu neměl.

317
Vývoj / Re:Ideálny programovací jazyk
« kdy: 15. 05. 2019, 16:58:02 »
Tak tady bych silně nesouhlasil. Jsem C++ programátor a od operátorů očekávám, že čertoviny dělat nebudou. A taky ve všech knihovnách, které používám, žádné čertoviny nedělají.
Třeba to, že se operátor > používal pro zápis do streamu (což je blokující operace, navíc může vyhodit výjimku), tu už se v C++ nedělá?
Zrovna iostreamy jsou obecně jedna z nejhůř navržených (a taky nejstarších) částí standardní knihovny obecně. Na druhou stranu zrovna tady je z kontextu dost jasné, že tenhle operator<< opravdu nedělá nic jako bitový posun. Naproti tomu se potkávám se spoustou matematických knihoven, kde operátory dělají přesně to, co od nich intuitivně čekám.
Citace
Úplně stejně očekávám od metod, že budou dělat to, co vyplývá z jejich jména.
To já také. Jenže u spousty typů je tolik různých variant, co může dělat add() nebo equals()… Třeba máte dvě instance reprezentující v DOM následující dva XML elementy:

Kód: [Vybrat]
<f:element xmlns:f="http://example.com/namespace" />
<x:element xmlns:x="http://example.com/namespace" />

equals() vracet true nebo false?
No ale tohle je přesně to, na co narážím. Funkce equals nebo operátor== můžou být úplně stejně neintuitivní a matoucí. Zákaz přetěžování operátorů nevyřeší vůbec nic. Když autor knihovny pojmenuje funkci blbě, tak je vlastně úplně jedno jaké přesné ascii znaky to jsou.
Citace
Opravdu Javisti automaticky počítají s tím, že uživatelsky implementovaný kód může dělat cokoliv? Na takovéhle prasení vážně nejsem zvyklý a celkem mě překvapuje.
S tím počítají všichni dobří programátoři. Nejde o to, že by ten kód dělal něco nepředvídatelného (i když i to se stává). Ale když mám třeba kolekci, za kterou mám lokální nebo dokonce síťovou databázi, počítám s tím, že volání add() může trvat dlouho nebo může skončit třeba síťovou výjimkou. Když volám equals() na databázové entitě, ověřím si, zda se identita zjišťuje podle primárního klíče, podle hodnot nebo podle čeho. A tak dále. U operátoru ale čekám, že budou jednoduché, nebudou blokovat, nebudou vyhazovat výjimky, budou mít jednoznačný význam.
No když mám objekt, co se tváří třeba jako matice, tak od + i od add budu čekat sčítání matic. Ani v jednom případě nebudu očekávat komunikaci se vzdálenou databází. Naopak kolekce, která potichu komunikuje s nějakou vzdálenou databází je dost zákeřná, pokud se tváří jako nějaká obyčejná. Tohle zase nemá s operátory společné prakticky nic.
Citace
V tom je operátor == v Javě opravdu trochu nešťastný, protože tam je potřeba vědět, že porovnává reference. Ale zrovna C++ to má stejně, nemýlím-li se.
V C++ se operátor== obvykle přetěžuje tak, aby porovnával hodnoty. Obecně je v C++ zvykem, pokud to jenom trochu jde, aby se všechno chovalo jako vestavěné typy. Ale c++ rozlišuje samotný objekt od ukazatele na něj. Takže nemusím vůbec řešit, jak porovnávat identitu dvou objektů. Porovnávám jejich adresy resp. hodnoty dvou ukazatelů.

318
Vývoj / Re:Ideálny programovací jazyk
« kdy: 15. 05. 2019, 15:42:50 »
Tenhle problém ale není omezený jenom na operátory. V jazyce, který umožňuje přetěžovat operátory, může prase napsat třeba operátor +, který nic nesčítá. V jazyce bez přetěžování napíše stejné prase funkci nebo metodu "add", která bude matoucí úplně stejně. Zákaz přetěžování operátorů tu nepomůže.
Operátory programátor vnímá jako součást jazyka a očekává od nich, že budou dělat to, co se od nich intuitivně čeká, a že se budou chovat slušně. I když C++ programátoři pravděpodobně čekají čertoviny i od operátorů. U metod naopak každý počítá s tím, že je to uživatelsky implementovaný kód a může dělat cokoli.
Tak tady bych silně nesouhlasil. Jsem C++ programátor a od operátorů očekávám, že čertoviny dělat nebudou. A taky ve všech knihovnách, které používám, žádné čertoviny nedělají. Úplně stejně očekávám od metod, že budou dělat to, co vyplývá z jejich jména. Ano, bugy se vyskytují, ale to i v součástech jazyka, takže tam rozdíl není.
Opravdu Javisti automaticky počítají s tím, že uživatelsky implementovaný kód může dělat cokoliv? Na takovéhle prasení vážně nejsem zvyklý a celkem mě překvapuje.

319
Vývoj / Re:Ideálny programovací jazyk
« kdy: 15. 05. 2019, 15:23:39 »
Lepší by pochopitelně bylo přetížení operátoru ==.
Bylo by to lepší jen při pohledu z rychlíku. Myslím, že programátor například neočekává, že mu při použití operátoru vypadne výjimka.

Některé jazyky umožňují přetěžovat operátory, což pak vede k tomu, že programátor nikdy neví, co se při použití operátoru stane. Java byla navržena jako jednoduchá, takže tohle záměrně neumožnila – a jediné přetížené (ve smyslu „implementované kódem v metodách“) operátory v Javě jsou ty pracující se Stringy. Přičemž samotný objekt String je v Javě final a má speciální podporu kompilátoru. Nebo-li autoři specifikace mohli zaručit, že se metody Stringu implementující operátory budou chovat slušně a operátory nebudou mít žádné nečekané efekty. Pokud byste operátor == přetížil jako volání equals() (a třeba i ošetřil null hodnoty), pořád bude použití toho operátoru volat uživatelský kód, který může vyhazovat výjimky, dělat dotaz do databáze, equals() ani nemusí být komutativní.

Přetížený operátor == by teprve byl pořádně kontraintuitivní.
Tenhle problém ale není omezený jenom na operátory. V jazyce, který umožňuje přetěžovat operátory, může prase napsat třeba operátor +, který nic nesčítá. V jazyce bez přetěžování napíše stejné prase funkci nebo metodu "add", která bude matoucí úplně stejně. Zákaz přetěžování operátorů tu nepomůže.

320
Vývoj / Re:Ideálny programovací jazyk
« kdy: 15. 05. 2019, 14:52:03 »
Integer v Javě je objekt, operátor == v Javě porovnává reference...
Dík, zmátlo mě to cachování malých integerů. Ani z toho, že == má porovnávat reference jsem nebyl schopný vydedukovat, co se tam děje.
Citace
To, že operátor == v Javě porovnává hodnoty primitivních typů a reference u objektů mi nijak neintuitivní nepřipadá.
Rozhodně je to nekonzistentní. že budou vestavěné typy a objekty podporovat jiné operace bych bral, že ale stejná operace funguje na obou jinak mi přijde jako past na nováčky.
Citace
Napadají mne jen dvě srovnatelně dobrá řešení a žádné lepší. Jedno řešení by bylo pro objekty == udělat jako alias pro equals() a ošetřit null hodnoty. Druhé řešení by bylo == pro objekty úplně zakázat. V obou případech by na porovnání referencí musel existovat nějaká systémová metoda.
Intuitivní by mi přišlo mít dvě porovnání, jedno na identitu a jedno na hodnotu, a nechat je chovat se konzistentně pro všechno. Samotná syntaxe těch dvou porovnání už je vlastně detail.

321
Vývoj / Re:Ideálny programovací jazyk
« kdy: 15. 05. 2019, 14:05:52 »
Java také nebude ten ideální jazyk...  8)
Kód: (Java) [Vybrat]
public class HelloWorld
{
  public static void main(String[] args)
  {
    Integer a = 1024;
    Integer b = 1024;
    System.out.print(a == b); // false
  }
}

Vysvětlil by mi někdo, co se tam děje? Kdyby to bylo něco mimo rozsah 32b intu, tak bych to pochopil. Ale 1024 je furt zatraceně málo.

322
Vývoj / Re:Ideálny programovací jazyk
« kdy: 10. 05. 2019, 11:40:26 »
Měl jsem na mysli hlavně velikost známou až v runtimu. Jedna věc jsou dočasné proměnné. Ty jsou v pohodě, i když najednou nutně potřebujeme registr pro frame pointer. Druhá věc je ale vracení objektu neznámé velikosti hodnotou. Volající neví kolik paměti vyhradit a volaný to taky nezvládne alokovat bez větších problémů. Musel by ten zásobník přeskládat. Neznám žádné volací konvence, které by něco takového uměly.
Já ty lowlevel detaily dobře neznám a C++ jsem viděl naposledy tak před deseti lety, takže mi asi spousta věcí uniká, ale čistě od stolu mě překvapuje, že je to problém. Přijde mi, že by stačily dvě čísla na začátku: velikost Derived a offset Base v rámci Derived. Pokud potřebuju Derived někam zkopírovat, vím jeho velikost a víc nepotřebuju. Pokud potřebuju šahat do Base, vím jeho offset, což je taky všechno, co potřebuju.
Uložit někam velikost není problém. Ten je v tom, že na zásobník se ukládají i návratové adresy a parametry při volání funkcí. Takže volající na zásobník nacpe parametry a pak se tam uloží i návratová adresa. Pokud volající zná přesnou velikost vraceného objektu, tak si může vyhradit lokální proměnnou a předat její adresu jako parametr. Pokud tu velikost nezná, tak má smůlu.
Volaný si může na zásobník nacpat co chce, jenže před koncem musí všechno zase uklidit aby na vrchu byla návratová adresa. Jinak by se nešlo vrátit. Mohl by pošoupnout parametry a návratovou hodnotu a tím vyhradit místo. Tohle je komplikace nejen na straně volaného, ale i volajícího, kterému by se pod rukama změnil stack pointer.

Běžná a poměrně důležitá optimalizace je vypuštění frame pointeru. Tím se ušetří jeden registr a zjednoduší prolog a epilog funkce. Pokud nejde v compile-time přesně modelovat věci na zásobníku, tak tuhle optimalizaci nemůžeme udělat. Variable length arrays nebo alloca v C tuhle optimalizaci znemožní v rámci jedné funkce. Tohle by prosáklo i ven. A navíc takovéhle skoky neznámé velikosti ztěžují kompilátoru adresování ostatních proměnných na zásobníku.

323
Vývoj / Re:Ideálny programovací jazyk
« kdy: 10. 05. 2019, 10:22:05 »
Co si mám představit pod "podporu objektů neznámého typu na zásobníku"? Funkce s těmi daty nic nemusí dělat, musí je umět jenom zkopírovat a vědět, kde začínají data, kterým rozumí. Ostatní může v klidu ignorovat, ne?
Měl jsem na mysli hlavně velikost známou až v runtimu. Jedna věc jsou dočasné proměnné. Ty jsou v pohodě, i když najednou nutně potřebujeme registr pro frame pointer. Druhá věc je ale vracení objektu neznámé velikosti hodnotou. Volající neví kolik paměti vyhradit a volaný to taky nezvládne alokovat bez větších problémů. Musel by ten zásobník přeskládat. Neznám žádné volací konvence, které by něco takového uměly.

324
Vývoj / Re:Ideálny programovací jazyk
« kdy: 09. 05. 2019, 22:13:23 »
To jsem ted uplne asi nepochopil, v C bych mel design takovy, ze polymorfismus budu delat jen  nad funkcemi, nikoliv nad strukturami. Nad strukturami navic asi uplne polymorfismus delat nepotrebuju.
Funkce k sobě obvykle potřebujou nějaké specifické data. Situace, že by všem polymorfním funkcím stačila stejná data mi přijde poměrně vzácná. Všechny rozumné callbacky, které berou nějaký pointer na funkci berou i nějaký void pointer na data. Cpát jim je v globálách sice jde, ale není to ono. Jinak C++ kód
Kód: [Vybrat]
class Base
{
public:
  virtual void foo();
  int a;
};
class Derived : public Base
{
  void foo() override;
  int b;
};
odpovídá C kódu :
Kód: [Vybrat]
struct Base
{
  struct Vft *vft;
  int a;
};
struct Derived
{
  struct Base base;
  int b;
};
struct Vft
{
  void (*foo)( Base *this );
};
+ 2 konstaty typu Vft s ukazateli na dvě verze funkce foo.
C++ k tomuhle dělá v podstatě jen syntaktický cukr, takže samo nastavuje pointery na Vft, automaticky konvertuje typy pointerů a zjednodušuje volání metod. Třeba v Cčkových hlavičkách pro windowsí COM objekty se dá najít, jak vypadá volání virtuálních funkcí C++ z C kódu. Implementace objektů v C vypadá obvykle velice podobně, jen se občas vypouští ta vft a pointery na funkce se cpou přímo do Base, pokud jich není moc. Kód, který dostane pointer na Base pak nemůže vědět, jestli je to Base, nebo začátek Derived. A pokud by tu Base zkopíroval, tak udělá slicing jako C++ (jen s drobným rozdílem, že v C++ se nebude slepě kopírovat ten pointer na vft).

Citace
Mimochodem jde v C udelat to, ze 1 hlavicka bude pro 2 ruzne implementace? Ze by pak hlavicka hrala roli interfacu (neplest prosim s OOP) k vicero implementacim?
Samozřejmě. Záleží jenom na tom, jaké obj soubory dostane linker. Nebo jaká verze .dll/.so se předhodí programu při startu. V C se funkce linkují čistě podle jména. Linker dokonce ani nemůže zkontrolovat typy, protože C na rozdíl od C++ nedělá name mangling.

325
Vývoj / Re:Ideálny programovací jazyk
« kdy: 09. 05. 2019, 16:21:33 »
ja jsem to uplne 100% nepochopil, ale doptavat uz se nebudu, tohle co pisete to uz je proste fakt moc. Ja nikdy proste v C++ delat nechci, protoze to je hruza. To si to radeji napisu v C a budu delat polymorfismus pres pointry na funkce.
Ale v C to přece vyjde na stejno. Pokud budu dělat polymorfismus Cčkovským stylem, tzn bázová struktura bude první položka té odvozené, tak jsou při kopírování té struktury úplně stejné problémy. Jenom to přetypování ukazatele z odvozené struktury na bázovou se musí napsat ručně. Pokud tu strukturu alokuju na haldě, tak je to stejně bezproblémové v C i C++. A pokud ji vytvořím na stacku, tak mi kód, který nic neví o odvozené struktuře, vyzobne a "zbastardizuje" tu strukturu i v čistém C. Zrovna tady přidává C++ jenom syntaktický cukr a principy z Cčka zůstávají.

326
Vývoj / Re:Ideálny programovací jazyk
« kdy: 09. 05. 2019, 12:45:23 »
Me na CPP stve, a doted mi nikdo nevysvetlil proc to tak je, neco cemu se da rika zbastardizovani objektu. To se vam tak snazim psat tak, aby se alokovalo na stacku, jenze na stacku neni proste mozne udelat polymorfismus. Kdyz se o to pokusim, tak c++ zbastardizuje objekt do predka a vytvori bastarda. Uz nevim jak se tomu presne rika, ja tomu rikam bastardizace.
Říká se tomu slicing. Je to důsledek toho, že v kontextu kdy neznáš kompletní typ objektu, tak je hodně těžké ho kopírovat. C++ zvolilo jedno z možných omezených řešení, jiné jazyky volí jiná omezení. Dobré řešení AFAIK není.

Problém není polymorfismus ale právě kopírování. Kód :
Kód: [Vybrat]
void foo( const Base & );
//...
Derived aaa;
foo( aaa );
funguje ok bez jakékoliv "bastardizace". Problém nastává třeba u
Kód: [Vybrat]
Base foo()
{
    Derived temp;
    return temp;
}
V místě, kde foo volám, o typu Derived nevím vůbec nic. Může to být v modulu, který se kompiloval v době, kdy Derived ještě vůbec neexistoval. Aby volající kód mohl kopírovat neznámý odvozený typ, musel by mít k dispozici něco jako "virtuální kopírovací konstruktor" + podporu objektů neznámého typu na zásobníku. To druhé bohužel hodně omezí optimalizátor v rozletu.
Spousta jazyků to řeší stylem všechno je na heapu a vůbec nic se nekopíruje. V porovnání se zásobníkem je halda obecnější a pomalejší. A třeba v hard realtime systémech je dynamická alokace na haldě hodně velký problém. Takže C++ šlo cestou že to dovolí, protože to programátor občas potřebuje.

Dobrý zvyk v C++ je, že pokud píšu "interface" nebo spíš třídu s virtuálními metodami, tak zakážu kopírování abych si nemohl naběhnout na vidle.

327
Vývoj / Re:Ideálny programovací jazyk
« kdy: 07. 05. 2019, 10:51:40 »
Nejdřív bych si ujasnil, k čemu má vlastně ten jazyk sloužit. Pak bych řešil, jestli je kvůli tomu nutné vytvářet nový jazyk. Teprve na základě toho bych pak případně řešil nějaký tým odborníků a zadání.
Tak nějak. Jazyk je nástroj. Jeho vlastnosti vycházejí převážně z toho, jaký problém se zrovna řeší. (A to opomíjím, že výběr programovacího jazyka je v reálu málo technické a hodně manažerské rozhodnutí.) Chtít ideální jazyk bez přesnější specifikace problému je jako chtít ideální dopravní prostředek, nebo kuchyňský spotřebič.

Stran: 1 ... 20 21 [22]