Jak můžu opustit funkci

PetrM

Re:Jak můžu opustit funkci
« Odpověď #225 kdy: 17. 07. 2018, 15:50:08 »
Taková chyba principiálně nemůže nestat. Transportní vrstva dodá buď bezchybnou zprávu, nebo nějakou chybu typu timeout při příjmu. Ale co je na tom výjimečného? To je na transportní vrstvě zrovna tak "normální" stav, jako poškozená zpráva na síťové vrstvě.
Výjimky nejsou výjimečné tím, že by k nim docházelo výjimečně málo často, ale tím, že je to výjimka z normálního běhu programu, odchylka od toho, co chci, aby program dělal. K chybám při síťovém transportu může docházet hodně často, ale program je dělaný proto, aby data úspěšně přenášel – neúspěšný přenos je odchylka od tohoto žádaného stavu, proto je to výjimka.

Ještě jinak.
Požadovaný stav je, že dojde správný paket a já ho potvrdím.
Chyba je, že dojde poškozený paket a snažím se to řešit (= NACK, aplikace samoopravnýho kódu,...).
Výjimka je, že se v půlce paketu přeruší spojení a ani po timeoutu nenavážu komunikaci s protistranou.

O level výš je chybějící/přebývající blok dat výjimka (přerušení lajny je furt výjimka - jiný stav je to na úrovni PHY/MAC), protože mám mít zajištěný kompletní data. Ale tam můžu mít třeba stav zprávy UNSIGNED/VALID/INVALID a se špatným podpisem se nastaví jako INVALID a nevolá se výjimka (a stav se prostě zobrazí uživateli).


PetrM

Re:Jak můžu opustit funkci
« Odpověď #226 kdy: 17. 07. 2018, 15:51:20 »
Je mnoho důvodů, proč nepoužívám proměnné typu boolean. Vystačím si s tímto:
Kód: [Vybrat]
if (isX()) {
...
}

Jaký návratový typ má funkce isX()?

Kit

Re:Jak můžu opustit funkci
« Odpověď #227 kdy: 17. 07. 2018, 15:59:12 »
Je mnoho důvodů, proč nepoužívám proměnné typu boolean. Vystačím si s tímto:
Kód: [Vybrat]
if (isX()) {
...
}
A když potřebuješ výsledek toho isX() vícekrát? (Ptám se pro kamaráda, co má v tom isX() přístup ke clusteru.)

Potřebuji ho vždy jen jednou.

Re:Jak můžu opustit funkci
« Odpověď #228 kdy: 17. 07. 2018, 16:05:12 »
Je mnoho důvodů, proč nepoužívám proměnné typu boolean. Vystačím si s tímto:
Kód: [Vybrat]
if (isX()) {
...
}
A když potřebuješ výsledek toho isX() vícekrát? (Ptám se pro kamaráda, co má v tom isX() přístup ke clusteru.)

Potřebuji ho vždy jen jednou.

Jak napíšeš test, že je splněná nějaká sada podmínek a přitom ještě zaloguješ vysvětlení?

.

Re:Jak můžu opustit funkci
« Odpověď #229 kdy: 17. 07. 2018, 16:32:59 »
Je zvláštní, že někteří lidé poté co vykonají velkou potřebu ve veřejném prostoru, mají ještě nutkání se v těch hovnech prohrabávat. Budiž.

Někde v polovině tohoto threadu jsem diskutujícím vytýkal, že pomíjejí kontext. Od té doby myslím jen Kiwi zdůraznil, že pokud píše v C, považuje následující za idiomatické. Různé jazyky mají různé pohledy na to, jak je dobré, aby kód vypadal. Většinou se vyplatí tohoto držet. Je komické se bavit o jediném exit pointu funkce v jazycích, které podporují výjimky, protože exit pointem může být jakékoliv volání funkce, které vyhodí výjimku (pokud to v dané funkci explicitně neošetřím, což zase podpírá smysl výjimek).

I když si Dijkstry považuji, nemyslím si že jeho téměř 50 let staré zásady strukturovaného programování nedoznaly za ta léta určitých změn a nelze je brát dogmaticky. Samozřejmě, že je lepší, když má funkce jen jeden exit point, ale abych toto pravidlo dodržel, nebudu kvůli tomu zavádět třeba 5 řídících proměných. Nakonec některé z těch zásad měly neméně slavné oponenty (Wirth, Knuth) a nemyslím, že kdokoliv z nás se komukoliv z nich rozhledem a vědomostmi alespoň přibližuje.

Abychom se dál nehrabali v těch hovnech, bylo by dobré, aby každý podpořil své tvrzení alespoň citátem nějaké uznávané autority. Takže pro začátek:

Nested conditional code often is written by programmers who are taught to have one exit point from a method. I've found that is a too simplistic rule. When I have no further interest in a method, I signal my lack of interest by getting out. Directing the reader to look at an empty else block only gets in the way of comprehension.
Martin Fowler - Refactoring


.

Re:Jak můžu opustit funkci
« Odpověď #230 kdy: 17. 07. 2018, 16:39:38 »
Pro mainstreamove/aplikacni programovani je to neocenitelny konstrukt.
A proto nové jazyky jako Rust nebo Go výjimky nemají?

Go je odpad.
A Rust má docela pěkné řešení ve stylu Left/Right, ale docela by mě zajímalo, jak to bude škálovat, když se člověk pustí do nějakého aplikačního vývoje a ne jen low-level.
Pokud jsi takhle hotov se vším, nemá smysl diskutovat. Ale u tebe mne to překvapilo. Nepříjemně.

Kit

Re:Jak můžu opustit funkci
« Odpověď #231 kdy: 17. 07. 2018, 16:41:58 »
Je mnoho důvodů, proč nepoužívám proměnné typu boolean. Vystačím si s tímto:
Kód: [Vybrat]
if (isX()) {
...
}
A když potřebuješ výsledek toho isX() vícekrát? (Ptám se pro kamaráda, co má v tom isX() přístup ke clusteru.)

Potřebuji ho vždy jen jednou.

Jak napíšeš test, že je splněná nějaká sada podmínek a přitom ještě zaloguješ vysvětlení?

Podmínky testuji sekvenčně. Každá zaloguje vysvětlení. Máš nějaký příklad?

Kit

Re:Jak můžu opustit funkci
« Odpověď #232 kdy: 17. 07. 2018, 16:47:13 »
Podmínky testuji sekvenčně. Každá zaloguje vysvětlení. Máš nějaký příklad?

Přesněji: Napiš ukázku, jak bys to udělal ty a já to refaktoruji do podoby, jak bych to dělal já.

totalbreak

Re:Jak můžu opustit funkci
« Odpověď #233 kdy: 17. 07. 2018, 17:04:44 »
Abychom se dál nehrabali v těch hovnech, bylo by dobré, aby každý podpořil své tvrzení alespoň citátem nějaké uznávané autority.

If you need more than 3 levels of indentation, you're screwed anyway, and should fix your program.

The goto statement comes in handy when a function exits from multiple locations and some common work such as cleanup has to be done. If there is no cleanup needed then just return directly.

Linus Torvalds, Linux kernel coding style

Kiwi

Re:Jak můžu opustit funkci
« Odpověď #234 kdy: 17. 07. 2018, 18:20:02 »
Taková chyba principiálně nemůže nestat. Transportní vrstva dodá buď bezchybnou zprávu, nebo nějakou chybu typu timeout při příjmu. Ale co je na tom výjimečného? To je na transportní vrstvě zrovna tak "normální" stav, jako poškozená zpráva na síťové vrstvě.
Výjimky nejsou výjimečné tím, že by k nim docházelo výjimečně málo často, ale tím, že je to výjimka z normálního běhu programu, odchylka od toho, co chci, aby program dělal. K chybám při síťovém transportu může docházet hodně často, ale program je dělaný proto, aby data úspěšně přenášel – neúspěšný přenos je odchylka od tohoto žádaného stavu, proto je to výjimka.

Ještě jinak.
Požadovaný stav je, že dojde správný paket a já ho potvrdím.
Chyba je, že dojde poškozený paket a snažím se to řešit (= NACK, aplikace samoopravnýho kódu,...).
Výjimka je, že se v půlce paketu přeruší spojení a ani po timeoutu nenavážu komunikaci s protistranou.

O level výš je chybějící/přebývající blok dat výjimka (přerušení lajny je furt výjimka - jiný stav je to na úrovni PHY/MAC), protože mám mít zajištěný kompletní data. Ale tam můžu mít třeba stav zprávy UNSIGNED/VALID/INVALID a se špatným podpisem se nastaví jako INVALID a nevolá se výjimka (a stav se prostě zobrazí uživateli).
"Požadovaný stav"? "Normální běh programu"? WTF?!
Žádný stav přeci není "požadovaný" a celý běh programu je "normální". Když si představím stavový diagram programu, nemám důvod některé uzly malovat nějak jinak. Program prostě reaguje na možné události a "chyba" je jen jednou z možných událostí. Záměrně píšu v uvozovkách, protože to je jen naše označení pro určitý stav. Ale to označení je dost zavádějící - chybou totiž ve skutečnosti je jakékoli neošetření/neuvažování možného stavu. Že mi nedojde paket je úplně stejně "normální" stav, jako že dojde. Pokud mám nabídku z 5 položek označených čísly 1-5, je stisk jakékoli klávesy stejně "normální". Přece není žádnou "chybou" pokud uživatel stiskne L a není důvod takovou situaci obsluhovat nějak zcela odlišně než číslice 1-5. Je to úplně normální situace, protože dotyčná funkce mi může vrátit cokoli, co se dá na klávesnici stisknout, a já s tím musím jako programátor počítat.

Jaký mají výjimky kladný efekt na návrh programu? Co je správného na reagování na určité stavy nějakým úplně jiným kanálem někde v úplně jiné části programu? Postnul jsem dva články, na něž Kit napsal, že autor výjimky použil chybně. A jak je to tedy správně?

LongGone

Re:Jak můžu opustit funkci
« Odpověď #235 kdy: 17. 07. 2018, 18:29:58 »
Pro mainstreamove/aplikacni programovani je to neocenitelny konstrukt.
A proto nové jazyky jako Rust nebo Go výjimky nemají?
Go je odpad.
Pokud jsi takhle hotov se vším, nemá smysl diskutovat. Ale u tebe mne to překvapilo. Nepříjemně.
Mnoho podprůměrných programátorů na Go nadává, takže by to nemělo překvapovat.

Re:Jak můžu opustit funkci
« Odpověď #236 kdy: 17. 07. 2018, 18:47:07 »
Pro mainstreamove/aplikacni programovani je to neocenitelny konstrukt.
A proto nové jazyky jako Rust nebo Go výjimky nemají?

Go je odpad.
A Rust má docela pěkné řešení ve stylu Left/Right, ale docela by mě zajímalo, jak to bude škálovat, když se člověk pustí do nějakého aplikačního vývoje a ne jen low-level.
Pokud jsi takhle hotov se vším, nemá smysl diskutovat. Ale u tebe mne to překvapilo. Nepříjemně.

Spousta veci stoji za dlouhe a peclive zvazeni.

Ale fakt ne Go, kde je zoufale videt, ze autori minuli 30 let vyvoje v programovacich jazycich a pak si rekli, ze to zkusi jeste jednou, tentokrat snad lepe.

Re:Jak můžu opustit funkci
« Odpověď #237 kdy: 17. 07. 2018, 19:09:10 »
"Požadovaný stav"? "Normální běh programu"? WTF?!
Žádný stav přeci není "požadovaný" a celý běh programu je "normální". Když si představím stavový diagram programu, nemám důvod některé uzly malovat nějak jinak. Program prostě reaguje a možné události a "chyba" je jen jednou z možných událostí. Záměrně píšu v uvozovkách, protože to je jen naše označení pro určitý stav. Ale to označení je dost zavádějící - chybou totiž ve skutečnosti je jakékoli neošetření/neuvažování možného stavu. Že mi nedojde paket je úplně stejně "normální" stav, jako že dojde. Pokud mám nabídku z 5 položek označených čísly 1-5, je stisk jakékoli klávesy stejně "normální". Přece není žádnou "chybou" pokud uživatel stiskne L a není důvod takovou situaci obsluhovat nějak zcela odlišně než číslice 1-5. Je to úplně normální situace, protože dotyčná funkce mi může vrátit cokoli, co se dá na klávesnici stisknout, a já s tím musím jako programátor počítat.
To je typický pohled programátora s klapkami na očích. Pro všechny ostatní je samozřejmě nějaký běh programu normální, a to takový, kvůli kterému ten program používají. Třeba když si chce uživatel vytisknout PDF dokument, je normální běh PDF prohlížeče takový, že uživateli nakonec z tiskárny vyleze papír s vytištěným dokumentem. Můžete mít v programu ošetřené úplně všechny chyby, ale pokud se uživateli ten dokument vytisknout nepodaří, bude oprávněně nadávat, že ten program je k ničemu.

Jeden extrém jsou programy, které s chybami vůbec nepočítají a neošetřují je. Druhý extrém jste popsal vy, a spočívá v tom, že se někdo soustředí jenom na ošetření chyb a zapomene, že kromě toho by ten program také měl ještě něco rozumného dělat.

Jaký mají výjimky kladný efekt na návrh programu? Co je správného na reagování na určité stavy nějakým úplně jiným kanálem někde v úplně jiné části programu? Postnul jsem dva články, na něž Kit napsal, že autor výjimky použil chybně. A jak je to tedy správně?
Správného je na tom to, že se na každý stav reaguje v té části programu, kde se na něj nějak reagovat dá. Například u toho tisku PDF může dojít k tomu, že v průběhu vykreslování stránky na tiskárnu dojde ke ztrátě spojení s tiskárnou. Vykreslovací kód s tím samozřejmě nic neudělá a ani s tím nic dělat nemá, na druhou stranu velice vhodné místo kde takovou událost řešit je kód pro interakci s uživatelem. Který může uživateli třeba zobrazit zprávu, že tiskárna bohužel přestala komunikovat, a nabídnout možnost vytisknout to na jiné tiskárně.

v

Re:Jak můžu opustit funkci
« Odpověď #238 kdy: 17. 07. 2018, 19:34:26 »
"Požadovaný stav"? "Normální běh programu"? WTF?!
Žádný stav přeci není "požadovaný" a celý běh programu je "normální". Když si představím stavový diagram programu, nemám důvod některé uzly malovat nějak jinak. Program prostě reaguje a možné události a "chyba" je jen jednou z možných událostí. Záměrně píšu v uvozovkách, protože to je jen naše označení pro určitý stav. Ale to označení je dost zavádějící - chybou totiž ve skutečnosti je jakékoli neošetření/neuvažování možného stavu. Že mi nedojde paket je úplně stejně "normální" stav, jako že dojde. Pokud mám nabídku z 5 položek označených čísly 1-5, je stisk jakékoli klávesy stejně "normální". Přece není žádnou "chybou" pokud uživatel stiskne L a není důvod takovou situaci obsluhovat nějak zcela odlišně než číslice 1-5. Je to úplně normální situace, protože dotyčná funkce mi může vrátit cokoli, co se dá na klávesnici stisknout, a já s tím musím jako programátor počítat.
To je typický pohled programátora s klapkami na očích. Pro všechny ostatní je samozřejmě nějaký běh programu normální, a to takový, kvůli kterému ten program používají. Třeba když si chce uživatel vytisknout PDF dokument, je normální běh PDF prohlížeče takový, že uživateli nakonec z tiskárny vyleze papír s vytištěným dokumentem. Můžete mít v programu ošetřené úplně všechny chyby, ale pokud se uživateli ten dokument vytisknout nepodaří, bude oprávněně nadávat, že ten program je k ničemu.

Jeden extrém jsou programy, které s chybami vůbec nepočítají a neošetřují je. Druhý extrém jste popsal vy, a spočívá v tom, že se někdo soustředí jenom na ošetření chyb a zapomene, že kromě toho by ten program také měl ještě něco rozumného dělat.

Jaký mají výjimky kladný efekt na návrh programu? Co je správného na reagování na určité stavy nějakým úplně jiným kanálem někde v úplně jiné části programu? Postnul jsem dva články, na něž Kit napsal, že autor výjimky použil chybně. A jak je to tedy správně?
Správného je na tom to, že se na každý stav reaguje v té části programu, kde se na něj nějak reagovat dá. Například u toho tisku PDF může dojít k tomu, že v průběhu vykreslování stránky na tiskárnu dojde ke ztrátě spojení s tiskárnou. Vykreslovací kód s tím samozřejmě nic neudělá a ani s tím nic dělat nemá, na druhou stranu velice vhodné místo kde takovou událost řešit je kód pro interakci s uživatelem. Který může uživateli třeba zobrazit zprávu, že tiskárna bohužel přestala komunikovat, a nabídnout možnost vytisknout to na jiné tiskárně.
to musí být skvělý pocit, rozumět úplně všemu

Kit

Re:Jak můžu opustit funkci
« Odpověď #239 kdy: 17. 07. 2018, 19:35:52 »
Jaký mají výjimky kladný efekt na návrh programu? Co je správného na reagování na určité stavy nějakým úplně jiným kanálem někde v úplně jiné části programu? Postnul jsem dva články, na něž Kit napsal, že autor výjimky použil chybně. A jak je to tedy správně?

Napsal jsem tohle:
Citace
Koukám, že výjimky v C++ jsou skutečně zlo, zejména když je někdo použije tak hloupým způsobem, jako autor těch článků.
Chceš to rozebrat?
Kód: [Vybrat]
try {
    ...
    int rc = fx ();
    if (rc != 0)
        throw std::exception ("Error!");
    ...
catch (std::exception &e) {
    handle_exception ();
}

Tady jsou hned 2 chyby: Použití std::exception a text "Error!". To značně omezuje strukturování výjimek. Nejdříve bys jí měl udělat potomka:
https://www.tutorialspoint.com/cplusplus/cpp_exceptions_handling.htm dole.
Potom můžeš výjimky rozlišovat dle typu. Dále je dobré do nich umístit místo vzniku, text a kódové označení výjimky - obvykle číslo, ale například databáze používají pětiznakový string.

Pokud tohle neuděláš, tak se můžeš klidně dál hádat, že výjimky jsou k ničemu. V surovém stavu, tedy takovém, v jakém nám je servíruje C++, jsou skutečně zlo. Hodně však pomůže, když místo "Error!" napíšeš co a kde se stalo. I použití dalších standardních výjimek může být užitečné, ale je jich málo.