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 ... 6 7 [8] 9 10 ... 22
106
Vývoj / Re:Pár otázok na C++
« kdy: 25. 11. 2020, 09:23:00 »
Zrovna Windows a Microsoft bych z téhle nekompatibility neobviňoval.

Ten problém přeci není v nekompatibilitě. Problém je v té knihovně, že se chová zmateně.
Ale ona se nechová zas tak zmateně. fwrite v C prostě u souborů otevřených v textovém režimu převádí '\n' na platformně závislé konce řádků a fread zase zpět. Pokud ten převod nechci, tak otevřu ten soubor jako binární. No a iostreamy v C++ se chovají stejně, aby v tom nebyl zmatek.

107
Vývoj / Re:Pár otázok na C++
« kdy: 24. 11. 2020, 16:47:47 »
nóó ale stejně je takový zajímavý žeto c++kový '\n' je schodný zrovinka se zakončením řádku v linuxu. bych se taky jako mohla zeptat proč jinde potřebujou mit něco extra a jestli to jako dneska ještě vůůůbec dává nějakej smysl :P :P ;D ;)
Jestli dneska ještě něco vůbec dává smysl je vedlejší, protože zpětná kompatibilita, žeáno. Wokna mají CRLF protože to tak měl DOS a ten, protože to tak mělo CP/M a ten, protože to tak chtěly staré teletextové mašiny. Jabčáci měli původně CR, ale ti se nekompatibilních změn evidentně nebojí, tak přešli na Unixové LF. U Microsoftu změna nehrozí, tam občas neopravují ani bugy ale přidávají nová rozhraní, protože by opravou rozbili háky, co ty bugy obcházejí.

108
Kus kódu, který zaručeně nemůže selhat IMHO není problém. Třeba pomocí typů toho lze dosáhnout velice snadno (jsem ze světa Haskell, Rust, etc C++ je samozřejmě jinej případ). FP taky udělají hodně práce. Všechny tyhle požadované záruky ti kvalitní typový systém může dát (neříkám, že na 100%, ale nenechme se rozptylovat podrobnostmi). Chápu, proč to tak komentuješ. Protože C++. Typy C++ a typy v Rust, to je jako mít a nemít.

Já jsem řešil syntax. Ta mě zajímá. Zdá se, že v tomto se trochu míjíme, protože ty se zahrabáváš do implementačních detailů a ještě navíc v C++.
Jo míjíme se. _Explicitně_ tu píšu o podobnostech mezi různými jazyky. Kus c++ jsem tu hodil jen proto, že sis několikrát psal o příklad syntaxe. Nikde tu IMO neřeším implementační detaily. c++ je to jen proto, že ho umím nejlíp a neřeším konkrétní jazyk ale principy.

Typy v Haskellu tohle moc neřeší. Jestli kus kódu může selhat nezávisí na jazyce, ale na tom, co ten kus kódu dělá. V Haskellu jsem toho napsal taky dost. Monáda ti ten "fail" bude propagovat nahoru úplně stejně neviditelně jako výjimky v c++. A v haskellu taky IMO nejde zaručit že kus monadického kódu ten fail nezavolá. A pure věci nakonec stejně musíš protlačit do toho stavového světa (nebo ten vnější RealWorld něčím prohnat ;) ).

Typy v C++ jsou hrubé, syntaxe je ošklivá, ale co do schopností jsou velmi mocné. C++ má jeden z nejsilnějších typových systémů ze všech mainstreamových jazyků. Kód ení moc hezký, ale principy jsou tam stejné jako ve zbytku světa. Takže prosím ignoruj jazyk a soustřeď se na principy. Ty jsou to o co mi jde.

109
Což je si ale, přiznejme si, nic moc.

Kód: [Vybrat]
# Python
with open('dog_breeds.txt') as src, threading.Lock(), db.connection() as con:
    con.insert(src.readlines())

(GoLang má defer, což je něco podobného ale hnusnějšího.)

Řekl bych, ty tak docela nepotřebuješ rozlišovat co může selhat a co ne. Jako spíše zajistit tu atomicitu.

Ten with řeší dvě věci, automaticky uzavřít zdroj, když něco selže, a rollback při chybě v bloku.

Tohle je zatím nejhezčí s čím jsem se setkal.
Já teď opravdu neřeším atomicitu, ale kusy kódu co zaručeně nemůžou selhat. I v jednom vlákně se ta transakčnost nedá zaručit pomocí with a podobných.
With, defer, tryWithResource a podobně umí jen to, co destruktory v c++ - zavolat kus kódu na konci bloku. (Taky se pomocí destruktorů dají celkem snadno implementovat). Pro tu transakci to nestačí. Např to with ještě potřebuje aby _každý_ resource uměl zaručeně neházející rollback (pomocí __exit__).

Svým kódem jsem se snažil ilustrovat tohle : Mám několik resourců, update každého může selhat a chci updatovat všechno nebo nic. Buďto můžu spočítat nový stav všech a pak je bez házení prohodit. Nebo můžu updatovat jeden po druhém, ale potřebuju možnost jak je bez házení vrátit zpět. Nevím, jak to udělat bez kusu kódu co zaručeně neselže.

Jádro je ten kus kódu co zaručeně nehází. Bez něho to AFAIK nejde. Destruktory, with, defer a podobné jsou jen bonus co ušetří mechanické bušení try-finally a podobného boilerplate kódu.

110
Mě víc zajímala ta syntaxe, jak si to @Jiří Havel představoval. Protože tam je IMHO ještě co objevovat a vylepšovat.
Já tu ale nepíšu o nějakých hypotetických nových jazycích. Já tu píšu o tom, jak se v c++ normálně píše kód se strong exception safety. Například mám třídu co má dvě dynamické pole stejné délky a metodu resize:
Kód: [Vybrat]
class Foo
{
private:
  std::unique_ptr<Bar[]> m_Bar;
  std::unique_ptr<Baz[]> m_Baz;
  size_t m_Size = 0;
public:
  void resize( size_t new_size )
  {
    std::unique_ptr bar( new Bar[new_size] ); // muze hodit
    std::unique_ptr baz( new Baz[new_size] ); // muze hodit
    // nějake kopirovani co muze hazet atd.

    // noexcept "commit" :
    m_Bar = std::move( bar ); // nebo swap( m_Bar, bar );
    m_Baz = std::move( baz );
    m_Size = new_size;
  }
}

O co mi šlo je, že ten házející a neházející kód se nijak neliší, takže při čtení od sebe nejdou poznat. Ty  výjimky prostě probublávají bez povšimnutí. A líbilo by se mi mít něco jako :
Kód: [Vybrat]
  void resize( size_t new_size )
  {
    std::unique_ptr bar( new Bar[new_size] ); // muze hodit
    std::unique_ptr baz( new Baz[new_size] ); // muze hodit
    // nějake kopirovani co muze hazet atd.

    noexcept {
      m_Bar = std::move( bar );
      m_Baz = std::move( baz );
      m_Size = new_size;
    }
[/quote]
Prostě říct překladači, kde nesmí nic lítat. A pokud bych tam zavolal něco co není noexcept tak aby to zahlásil.

Jinak podobnost se zmiňovanými funkcionálními myšlenkami není vůbec náhodná. Ten házející kód vytváří nový stav pokud možno s minimem vedlejších efektů. A viditelné vedlejší efekty se stanou v té commit fázi.

111
Děkuji za příspěvek.

Na jednu stranu je to co píšeš dost inspirativní. Na druhou stranu si nejsem úplně jist, zda tě dobře chápu.

Cítím v tvém popisu defer z Go. Taky mi přijde, že mluvíš vlastně o určité podobě transakcí - kód změní stav, a pokud vznikne chyba, tak se vrátí původní stav. Je to to co myslíš? Jak se práce se stavem promítne do věcí jako side effects (zapisování do souboru, posílání emailu)? Nechtěl by si napsat nějakou ukázku kódu, jak by to mělo fugovat?

To co popisuješ, existuje to v nějakém jazyce, nebo je to jen studie/úvaha?

Dělal jsem si jednu studii, kdy jsem měl jazyk, který si jednak hlídal při kompilaci, zda jsou všechny scénáře pokryty, zda nemůže dojít k nějaké neošetřené chybě. A dále si při každém spuštění apky kontroloval, zda jsou dostupné externí závislosti (nainstalované knihovny, dostupné externí rutiny/binárky, dostupnost k databázi, filesystému). Čímž jsem chtěl zajistit, aby vlastní běh té aplikace nemohl selhat.
Jestli by měl z mého příspěvku být cítit nějaký jazyk, tak C++. O exception safety se primárně mluví právě v souvislosti s c++ i když je to obecnější koncept. Ale právě v c++ je tohle uvažování vcelku běžné. Strong exception safety jsou transakce, jen se neřeší atomičnost z pohledu jiných vláken.

Zápis do souboru jako transakce je myslím poměrně známý postup :
- Vytvořím pomocný soubor zapíšu ho a flushnu na disk. Pokud tohle selže, pak je původní soubor stále netknutý.
- Přejmenuju pomocný soubor. Pokud má tahle operace strong exception safety, pak ji bude mít i celý zápis souboru.

A stejně se dá uvažovat i o jednotlivých objektech programu. Např při přidávání do dynamického pole mi může selhat alokace, nebo kopírování nějakého objektu. Takže alokuju nový kus paměti, všechno do něj nakopíruju a nakonec swapnu odkaz na nový blok paměti.

Obecně pokud mám swap, který dokáže prohodit vnitřnosti objektů bez možných výjimek, pak se na tom dá stavět transakční chování pro větší a větší bloky programu. A dobrým zvykem je, pokud je to možné, dávat vlastním objektům rozumný swap který jen prohodí ukazatele a nemůže házet.

112
Pokud může házet úplně všechno, pak se dost blbě udržujou invarianty objektů. Daleko lepší je házející kus a pak commit co nic házet nesmí. Při čtení kódu ale jednoduše nepoznám, kde zrovna jsem.
Můžeš to prosím rozvést?
Myslel jsem konkrétně "strong exception safety". Takže operace buď projde, nebo se komplet rollbackne. To se obvykle dělá tak, že se spočítá celý nový stav a ten se pak swapne s tím starým. Výpočet nového stavu může házet podle libosti, ale swap nesmí. A teď jak zaručit že nic v tom swapu nehází.

Pokud může házet cokoliv, tak se dá maximálně dosáhnout "basic exception safety". Takže po vyhození výjimky nic neleakuje, ale stav je nějak změněný a musím si ho nějak vyresetovat. Jo, invarianty jednotlivých objektů jsou obvykle ok. To jsem napsal trochu blbě. Myslel jsem spíš něco jako návrat programu do stavu před (high level) operací, co tu výjimku vyhodila.

Takže problém je v tom, že potřebuju bloky kódu o kterých si můžu být jistý že nehází. Můžu zkontrolovat jednotlivé funkce a ověřit podle typu nebo dokumentace. Ale tuhle tupou mechanickou činnost bych rád nějak přehodil na překladač. Navíc to není při letmém čtení kódu nijak vidět. Můžu přidat komentář, který kus nehází, ale ten co do toho bude koukat po mně stejně neví, jestli tomu komentáři může věřit.
Ani checked exceptions to zas tak moc neřeší. U nich vím co může z funkce lítat, ale pokud chci vědět i odkud, tak musím hledat.

Zrovna chyby jsou místo, kde je pomoc překladače obzvlášť potřeba. Protože řešení chyb a nestandardních situací je vždycky ten nejmíň otestovaný a nejvíc zabugovaný kus projektu. A to díky tomu, že jsou ty situace vzácné.

113
Ale kritika výjimek mě zajímá. Idris zmínil, že je pak těžší zajistit typovou bezpečnost, ok.
Jestli tě zajímá kritika výjimek, tak bych měl i další drobnost.

Výjimky IMO oddělují tu standardní a nestandardní cestu až moc dokonale. Jeden extrém je manuální ošetřování chyb furt dokola. Druhý extrém ale je, když při čtení kódu netuším, kde to může a nemůže vyletět.
Pokud může házet úplně všechno, pak se dost blbě udržujou invarianty objektů. Daleko lepší je házející kus a pak commit co nic házet nesmí. Při čtení kódu ale jednoduše nepoznám, kde zrovna jsem.

V tomhle se mi hrozně líbila jedna z posledních přednášek Herba Suttera - jen označit řádky (nebo možná celý blok) co můžou házet a bude se to propagovat nahoru. Překladač by pak mohl zkontrolovat že ty neoznačené kusy házet nemůžou. Tohle by mi přišlo jako rozumný kompromis. Propagace by byla automatická, ale při čtení by bylo vidět, odkud to může lítat.

114
Haskelliho Maybe/Either taky není jen hodnota. Vždycky vracíš dvojici.
Jedna věc je jak je to interně udělané a druhá jak se to používá. U Maybe/Either o tom nemusím uvažovat jako o dvojici. A nemám šanci tu interní dvojici nějak rozdrbat.

Neděláme vlastně všechno zapouzdření právě proto, abychom se tím interním stavem nemuseli zabývat?
V hlavách bych neškrtal, vždyť ten null se občas hodí.
A to je IMO ta esence toho bilionového omylu. Null se hodí občas, ne vždycky. Pro občasné použití se daleko líp hodí věcí jako optional, Maybe a jim podobné. Problém je, pokud ten null není ani opt out.

Každý nesmyslný ale reprezentovatelný stav musím řešit na každé úrovni, kde nemám pod kontrolou vstupy. A když je toho opravdu hodně jako těch nullů, tak je takřka jisté že někdo něco zapomene nebo se na to vykašle.

115
Jsem silně poznamenaný funkcionálním programováním a způsob ošetřování chyb v Go se mi extrémně nelíbí.

V žádném jazyce, co má rozumné součtové typy a pattern matching, jsem neviděl že by někdo vracel chyby tuplem. Ono to nedává smysl. Obvyke nechci vrátit hodnotu A chybu, ale hodnotu NEBO chybu. Go mě nutí aby každý typ měl nějakou defaultní/prázdnou/nesmyslnou hodnotu, kterou můžu vrátit v případě chyby, i když jinak není k ničemu a ani nedává smysl.

Až moc mi to připomíná Hoareho bilionový omyl.

Z Go mám nepříjemný pocit promrhaného potenciálu. Ten jazyk by mohl být o tolik lepší, kdyby jeho autoři (záměrně?) neignorovali skoro všechno "nové" kolem překladačů a jazyků.

116
Vývoj / Re:Discriminated unions v C++
« kdy: 23. 10. 2020, 16:39:46 »
Myslím, že najväčší problém je, že sa k tomu vyjadrujú tí, ktorí nielen že nepoznajú odpoveď a ani nechápu otázku, čo sú, podľa mňa, všetci okrem #1 a #5.

Pattern matching priamo zabudovaný C++ zatiaľ nemá, ale dá sa napísať aj jednoduchšie ako v tej peknej ukážke v #5, a skoro sa to na pattern matching podobá.

No, zdá se mi, že jsi si nepřečetl pořádně otázku. Podle té má mít typ Currency další dvě varianty,

Kód: [Vybrat]
Another of (currencyName : string) * decimal
| None

které se ale v toUSD nepoužijí (není to úplná funkce). Vyřešil jsi tedy jinou otázku. Tím nechci říct, že tvá odpověď neobsahuje užitečné informace, spíš tě chválím, že jsi své odpovědi #6 a #7 vynechal ze seznamu těch, u kterých tvrdíš, že porozuměly zadání.

Mimochodem, jak by se pomocí std::variant rozšířil typ Currency tak, aby odpovídal původnímu zadání, a jak by vypadala příslušná toUsd, to by mě docela zajímalo.
To rozšíření je celkem jednoduché, ne?
Pro another tam přidat :
Kód: [Vybrat]
struct AnotherCurrency
{
  std::string name;
  double value;
};
A jako prázdný chlívek pro none je v C++ knihovně prázdný typ std::monostate, který je myšlený právě pr prázdný variant.
Samozřejmě že s těmahle variantama se toUSD jako totální funkce napsat nedá.

A pak je taky samozřejmě problém double. Cpát peníze do doublu není dobrý nápad. Pro čísla ekonomická je nějaká astronomická přesnost naprosto nedostatečná. Takže to chce nějakou arbitrary precision libku. V boostu myslím nějaká byla.

117
Vývoj / Re:Discriminated unions v C++
« kdy: 22. 10. 2020, 09:33:46 »
Co takhle si udělat otagovaný decimal a cpát do variantu ten? Pak budou dolary a eura různé typy.

118
Distribuce / Re:Ubuntu pro náctiletou?
« kdy: 19. 10. 2020, 23:07:47 »
A neocenila by ta náctiletá spíš tohle Ubuntu? https://www.artzolo.com/craft/ubuntu-orange-stacking-wooden-toy? :P

119
Studium a uplatnění / Re:Start Java programování
« kdy: 15. 10. 2020, 11:04:20 »
... alebo  Herbert Schildta.
Jeho knížky o Javě jsou dobré? Protože co spáchal o C a C++ dalo vzniknout výrazu "bullschildt", jak to bylo zlé.

120
/dev/null / Re:Co může policie?
« kdy: 14. 10. 2020, 17:46:31 »
Můžou to řešit jako přestupek a napařit ti pokutu. Mám pocit, že až nějakých 20kkč. A jestli je nasereš, tak oči mhouřit nejspíš nebudou.

Stran: 1 ... 6 7 [8] 9 10 ... 22