Fórum Root.cz
Hlavní témata => Vývoj => Téma založeno: novomente 18. 08. 2019, 09:57:48
-
Zdravím,
použil jste někdy někdo příkaz "goto" v jazyku C v programátorské praxi?
-
Ano. I v C++ i v C#.
Kazdopadne rozhodne nejde o beznou vec, ale jsou urcite situace, kde se to hodi. Odhaduju to tak na jeden blok kodu rizeny pres GOTO za 5 let ;-)
-
mnohokrat ;)
Tiez pozri na https://koblents.com/Ches/Links/Month-Mar-2013/20-Using-Goto-in-Linux-Kernel-Code/
https://www.google.com/search?q=number+of+gotos+in+linux+kernel
atd.
-
použil jste někdy někdo příkaz "goto" v jazyku C v programátorské praxi?
Záleží na stylu programování. Někdy to téměř vyžaduje.
err = a_init();
if (err)
goto Exit;
err = b_init();
if (err)
goto a;
err = c_init();
if (err)
goto b;
. . .
goto Exit;
. . .
c:
c_finit();
b:
b_finit();
a:
a_finit();
Exit:
return err;
}
A variace na podobné téma (ve Windows kernelu se dalo najít celkem běžně).
-
Goto? Nikdy. A to delam programatora vice jak 20 let.
-
Ano. Na už zmíněný error handling. Víceméně jako náhradu výjimky. Jde asi o jediný celkem akceptovaný scénář pro goto.
Ještě se používá v konečných automatech a parserech, tam ho ovšem typicky nepíšete ručně, ale generujete.
-
Obcas, krome uz zminenych pripadu se hodi na vyskakovani z vicenasobne vnorenych smycek. Nekdy dost hodne. Na tom je obcas pekne poznat nezkuseneho programatora, ktery vyrobi strasne slozity a nepochopitelny bazmek, kde na prvni pohled vubec neni poznat co byl zamer, protoze ve skole se dozvedel, ze goto je zlo a ted ma strach ho pouzit. :)
-
Obcas, krome uz zminenych pripadu se hodi na vyskakovani z vicenasobne vnorenych smycek. Nekdy dost hodne. Na tom je obcas pekne poznat nezkuseneho programatora, ktery vyrobi strasne slozity a nepochopitelny bazmek, kde na prvni pohled vubec neni poznat co byl zamer, protoze ve skole se dozvedel, ze goto je zlo a ted ma strach ho pouzit. :)
Pouziti GOTO mi pripada jako "ted vyskoc z okna" ono to nejak dopadne. Misto: nech toho co delas, vyjdi dverma, zamkni a sejdi ze schodu dolu.
-
Obcas, krome uz zminenych pripadu se hodi na vyskakovani z vicenasobne vnorenych smycek. Nekdy dost hodne. Na tom je obcas pekne poznat nezkuseneho programatora, ktery vyrobi strasne slozity a nepochopitelny bazmek, kde na prvni pohled vubec neni poznat co byl zamer, protoze ve skole se dozvedel, ze goto je zlo a ted ma strach ho pouzit. :)
Tak ono nektere jazyky pro toto maji specialni syntaxi (break: navesti, priapdne break cislo_z_kolika_smycek_vyskocit) aby se nemuselo pouzit to zle skarede goto :-) .
-
Obcas, krome uz zminenych pripadu se hodi na vyskakovani z vicenasobne vnorenych smycek. Nekdy dost hodne. Na tom je obcas pekne poznat nezkuseneho programatora, ktery vyrobi strasne slozity a nepochopitelny bazmek, kde na prvni pohled vubec neni poznat co byl zamer, protoze ve skole se dozvedel, ze goto je zlo a ted ma strach ho pouzit. :)
Pouziti GOTO mi pripada jako "ted vyskoc z okna" ono to nejak dopadne. Misto: nech toho co delas, vyjdi dverma, zamkni a sejdi ze schodu dolu.
To je poradny nesmysl, C++ (nevim jak C, ale predpokladam, ze to bude stejny), je presne definovano jak se to bude chovat. Je to normalni vyskoceni ze vsech zanorenych scope. Zadne vyskakovani z okna, je to primy vychod ven. Promin, ale ty jsi dalsi takovy pripad, o kterem jsem mluvil....
-
Pouziti GOTO mi pripada jako "ted vyskoc z okna" ono to nejak dopadne.
Očividně jste dobře naučený to oblíbené "zapomeňte na goto". Skok uvnitř funkce je totiž v C naprosto legální a nemá žádné nepředvídatelné následky.
-
Obcas, krome uz zminenych pripadu se hodi na vyskakovani z vicenasobne vnorenych smycek. Nekdy dost hodne. Na tom je obcas pekne poznat nezkuseneho programatora, ktery vyrobi strasne slozity a nepochopitelny bazmek, kde na prvni pohled vubec neni poznat co byl zamer, protoze ve skole se dozvedel, ze goto je zlo a ted ma strach ho pouzit. :)
Pouziti GOTO mi pripada jako "ted vyskoc z okna" ono to nejak dopadne. Misto: nech toho co delas, vyjdi dverma, zamkni a sejdi ze schodu dolu.
To je poradny nesmysl, C++ (nevim jak C, ale predpokladam, ze to bude stejny), je presne definovano jak se to bude chovat. Je to normalni vyskoceni ze vsech zanorenych scope. Zadne vyskakovani z okna, je to primy vychod ven. Promin, ale ty jsi dalsi takovy pripad, o kterem jsem mluvil....
Presne tak, akorat ze tusim u C narozdil od C++ ti to dovoli preskocit inicializace promennych, coz neni zrovna super ale pokud ma clovek zapnute warningy tak si toho vsimne u u toho C
-
Kdyz tedy pouziji goto uvnitr nejakeho bloku kodu a vyskocim z tohoto bloku, povazuje prekladac zmineny blok kodu (ze ktereho jsem vyskocil) za ukonceny? Nebo ho nechava nejak otevreny? Viz tento priklad:
int i, j;
for(i = 0; i < 10; ++i) {
for(j = 0; j < 20; ++j) {
if(j == 5)
goto vylez_z_cyklu;
}
}
vylez_z_cyklu: printf("j je rovno %d\n", j);
-
Kdyz tedy pouziji goto uvnitr nejakeho bloku kodu a vyskocim z tohoto bloku, povazuje prekladac zmineny blok kodu (ze ktereho jsem vyskocil) za ukonceny? Nebo ho nechava nejak otevreny? Viz tento priklad:
int i, j;
for(i = 0; i < 10; ++i) {
for(j = 0; j < 20; ++j) {
if(j == 5)
goto vylez_z_cyklu;
}
}
vylez_z_cyklu: printf("j je rovno %d\n", j);
Samozrejme ze za ukonceny, proste si v tom miste odesel. Je to jako by si tam dal break; a za tim vnitrnim forem byl zase break;
-
Kdyz tedy pouziji goto uvnitr nejakeho bloku kodu a vyskocim z tohoto bloku, povazuje prekladac zmineny blok kodu (ze ktereho jsem vyskocil) za ukonceny? Nebo ho nechava nejak otevreny? Viz tento priklad:
int i, j;
for(i = 0; i < 10; ++i) {
for(j = 0; j < 20; ++j) {
if(j == 5)
goto vylez_z_cyklu;
}
}
vylez_z_cyklu: printf("j je rovno %d\n", j);
Co vám brání si to zkompilovat a pak to disasseblovat, aby jste viděl, jak to dopadlo?
-
Kdyz tedy pouziji goto uvnitr nejakeho bloku kodu a vyskocim z tohoto bloku, povazuje prekladac zmineny blok kodu (ze ktereho jsem vyskocil) za ukonceny? Nebo ho nechava nejak otevreny? Viz tento priklad:
int i, j;
for(i = 0; i < 10; ++i) {
for(j = 0; j < 20; ++j) {
if(j == 5)
goto vylez_z_cyklu;
}
}
vylez_z_cyklu: printf("j je rovno %d\n", j);
Co vám brání si to zkompilovat a pak to disasseblovat, aby jste viděl, jak to dopadlo?
Tak teoreticky mu muze chybet znalost ASM ;-)
https://godbolt.org/z/elNcJ8
-
https://godbolt.org/z/elNcJ8
Jeste doporucuji si pohrat s argumentama pro kompilaci napriklad uz i pri -O1 se kompletne zrusi ten cyklus, jelikoz kompilator vi ze muze rovnou vypsat cislo 5
-
Kdyz tedy pouziji goto uvnitr nejakeho bloku kodu a vyskocim z tohoto bloku, povazuje prekladac zmineny blok kodu (ze ktereho jsem vyskocil) za ukonceny? Nebo ho nechava nejak otevreny? Viz tento priklad:
int i, j;
for(i = 0; i < 10; ++i) {
for(j = 0; j < 20; ++j) {
if(j == 5)
goto vylez_z_cyklu;
}
}
vylez_z_cyklu: printf("j je rovno %d\n", j);
Co vám brání si to zkompilovat a pak to disasseblovat, aby jste viděl, jak to dopadlo?
Tak teoreticky mu muze chybet znalost ASM ;-)
https://godbolt.org/z/elNcJ8
:D compilace/disassembling je docela dobry napad :)
Ale jak uz bylo receno, brani mi v tom znalost ASM. Mimochodem, taky bych chtel trochu ten ASM okusit.
https://godbolt.org/z/elNcJ8 (https://godbolt.org/z/elNcJ8) - to je dobry link, diky moc :)
-
:D compilace/disassembling je docela dobry napad :)
Ale jak uz bylo receno, brani mi v tom znalost ASM. Mimochodem, taky bych chtel trochu ten ASM okusit.
https://godbolt.org/z/elNcJ8 (https://godbolt.org/z/elNcJ8) - to je dobry link, diky moc :)
To je škoda, by jste viděl, že to je prostě strojová instrukce jmp (skok na adresu) a že těch jmp je tam normálně víc. Jak píše Linus Torvalds: Každý if je goto.
-
To je škoda, by jste viděl, že to je prostě strojová instrukce jmp (skok na adresu) a že těch jmp je tam normálně víc. Jak píše Linus Torvalds: Každý if je goto.
+1 je treba to brat tak, ze goto neni zadny zlo, to z nej muze udelat jen programator. Obecne by programatori mohli mit nejakej prehled o tom, jak vlastne funguje ulozeni dat v pameti, volani funkci apod. kraviny na urovni HW. Tuhle jsem se s jednim 'pro- programatorem' hadal, kdyz se me snazil presvedcit o tom, ze dnesni CPU zpracovavaji OOP kod lepe, nez kod funkcionalni. Marne chapal, ze cpu nezna neco jako 'oop kod'
-
Na to že som v Cečku programoval už relativne dosť, tak ja ani neviem o existencii "GOTO" v tomto jazyku. Takže si myslím, že je to absolutne nepoužívané a asi to má aj nejaký dôvod.
-
Na to že som v Cečku programoval už relativne dosť, tak ja ani neviem o existencii "GOTO" v tomto jazyku. Takže si myslím, že je to absolutne nepoužívané a asi to má aj nejaký dôvod.
Důvodem je, že goto se dá snadno zneužít a tudíž je v rámci výuky zavedeno jednoduché pravidlo: "Nepoužívejte goto, nebo skončíte bez bodů".
Přečtěte si následující thread. Jsou tam všechny podstatné citace i ukázky.
https://koblents.com/Ches/Links/Month-Mar-2013/20-Using-Goto-in-Linux-Kernel-Code/
-
:D compilace/disassembling je docela dobry napad :)
Ale jak uz bylo receno, brani mi v tom znalost ASM. Mimochodem, taky bych chtel trochu ten ASM okusit.
https://godbolt.org/z/elNcJ8 (https://godbolt.org/z/elNcJ8) - to je dobry link, diky moc :)
To je škoda, by jste viděl, že to je prostě strojová instrukce jmp (skok na adresu) a že těch jmp je tam normálně víc. Jak píše Linus Torvalds: Každý if je goto.
Proto je lepsi se if-um vyhybat :-). Taky proto mozna vznikaji jazyky ktery maji polymorphic dispatch, pattern matching a podobne.... (a ano je to taky prevleceny goto... )
Podle me se to proste hur cte...
Kompiler at si tam naseka jmp kolik chce.... ale proc to mam cist ja?
A jeste sem tu nevidel link na https://homepages.cwi.nl/~storm/teaching/reader/Dijkstra68.pdf (https://homepages.cwi.nl/~storm/teaching/reader/Dijkstra68.pdf)
-
:D compilace/disassembling je docela dobry napad :)
Ale jak uz bylo receno, brani mi v tom znalost ASM. Mimochodem, taky bych chtel trochu ten ASM okusit.
https://godbolt.org/z/elNcJ8 (https://godbolt.org/z/elNcJ8) - to je dobry link, diky moc :)
To je škoda, by jste viděl, že to je prostě strojová instrukce jmp (skok na adresu) a že těch jmp je tam normálně víc. Jak píše Linus Torvalds: Každý if je goto.
Proto je lepsi se if-um vyhybat :-). Taky proto mozna vznikaji jazyky ktery maji polymorphic dispatch, pattern matching a podobne.... (a ano je to taky prevleceny goto... )
Podle me se to proste hur cte...
Kompiler at si tam naseka jmp kolik chce.... ale proc to mam cist ja?
A jeste sem tu nevidel link na https://homepages.cwi.nl/~storm/teaching/reader/Dijkstra68.pdf (https://homepages.cwi.nl/~storm/teaching/reader/Dijkstra68.pdf)
Tak goto se cte skvele a o te praci se pise hned v nekolika odkazech co jsou tu ve vlakne. Ta prace je holt stara a jeji hodnota je minimalne spekulativni.
-
:D compilace/disassembling je docela dobry napad :)
Ale jak uz bylo receno, brani mi v tom znalost ASM. Mimochodem, taky bych chtel trochu ten ASM okusit.
https://godbolt.org/z/elNcJ8 (https://godbolt.org/z/elNcJ8) - to je dobry link, diky moc :)
To je škoda, by jste viděl, že to je prostě strojová instrukce jmp (skok na adresu) a že těch jmp je tam normálně víc. Jak píše Linus Torvalds: Každý if je goto.
Proto je lepsi se if-um vyhybat :-). Taky proto mozna vznikaji jazyky ktery maji polymorphic dispatch, pattern matching a podobne.... (a ano je to taky prevleceny goto... )
Podle me se to proste hur cte...
Kompiler at si tam naseka jmp kolik chce.... ale proc to mam cist ja?
A jeste sem tu nevidel link na https://homepages.cwi.nl/~storm/teaching/reader/Dijkstra68.pdf (https://homepages.cwi.nl/~storm/teaching/reader/Dijkstra68.pdf)
Tak goto se cte skvele a o te praci se pise hned v nekolika odkazech co jsou tu ve vlakne. Ta prace je holt stara a jeji hodnota je minimalne spekulativni.
Ta "prace" neni stara. Nas obor neni stary. Od ty doby co to napsal se v nasem oboru nic moc nezmenilo.
A nevim co znamena, ze hodnota je minimalne spekulativni... jakoze by se o ni nemelo moc spekulovat?
-
:D compilace/disassembling je docela dobry napad :)
Ale jak uz bylo receno, brani mi v tom znalost ASM. Mimochodem, taky bych chtel trochu ten ASM okusit.
https://godbolt.org/z/elNcJ8 (https://godbolt.org/z/elNcJ8) - to je dobry link, diky moc :)
To je škoda, by jste viděl, že to je prostě strojová instrukce jmp (skok na adresu) a že těch jmp je tam normálně víc. Jak píše Linus Torvalds: Každý if je goto.
Proto je lepsi se if-um vyhybat :-). Taky proto mozna vznikaji jazyky ktery maji polymorphic dispatch, pattern matching a podobne.... (a ano je to taky prevleceny goto... )
Podle me se to proste hur cte...
Kompiler at si tam naseka jmp kolik chce.... ale proc to mam cist ja?
A jeste sem tu nevidel link na https://homepages.cwi.nl/~storm/teaching/reader/Dijkstra68.pdf (https://homepages.cwi.nl/~storm/teaching/reader/Dijkstra68.pdf)
Jo jasne, je lepsi se vyhybat ifum, ale pattern matching je cesta... haha, tak ty jsi to rozsekl frajere...
-
:D compilace/disassembling je docela dobry napad :)
Ale jak uz bylo receno, brani mi v tom znalost ASM. Mimochodem, taky bych chtel trochu ten ASM okusit.
https://godbolt.org/z/elNcJ8 (https://godbolt.org/z/elNcJ8) - to je dobry link, diky moc :)
To je škoda, by jste viděl, že to je prostě strojová instrukce jmp (skok na adresu) a že těch jmp je tam normálně víc. Jak píše Linus Torvalds: Každý if je goto.
Proto je lepsi se if-um vyhybat :-). Taky proto mozna vznikaji jazyky ktery maji polymorphic dispatch, pattern matching a podobne.... (a ano je to taky prevleceny goto... )
Podle me se to proste hur cte...
Kompiler at si tam naseka jmp kolik chce.... ale proc to mam cist ja?
A jeste sem tu nevidel link na https://homepages.cwi.nl/~storm/teaching/reader/Dijkstra68.pdf (https://homepages.cwi.nl/~storm/teaching/reader/Dijkstra68.pdf)
Jo jasne, je lepsi se vyhybat ifum, ale pattern matching je cesta... haha, tak ty jsi to rozsekl frajere...
Co je spatneho na pattern matching?
-
Jestli je goto v assembleru pouze instrukce JMP (a jeji vysledek ve strojovem kodu je vlastne take jenom skok na adresu), pak by melo goto teoreticky zkracovat strojovy kod, nez goto obchazet. Pokud platnost navesti (a tim i platnost goto) je pouze uvnitr funkce, nemelo by to sekat nejake dlouhe strojaky. Otazkou je, jestli se to kvuli rychlosti vyplati... viz dale...
V knize "Programovaci jazyk C" od K&R se pise (cituji): "Jazyk C poskytuje neomezeně zneužitelný příkaz goto a návěští, na která lze skákat. Formálně je příkaz goto vždzy nahraditelný a v praxi je téměř vždy jednoduché psát programy bez goto.", a o kus dále: "Existuje nicméně několik situací, kdy je možné goto použít."
Ony mozne pripady, kdy je goto MOZNE pouzit, byly zmineny v zacatku teto diskuse.
Dale na konci kapitoly o goto K&R pisou: "Kromě pár zde uvedených výjimek jsou programy používající goto složitější na pochopení a údržbu než programy bez goto. I když nechceme být příliš dogmatičtí, příkazy goto by měly být používány velice zřídka, nejlépe vůbec."
A jak je tedy na tom praxe? To je muj dotaz.
(citáty jsou z knihy: Programovací jazyk C; Brian W. Kernighan, Dennis M. Ritchie; Computer Press Brno 2013).
-
estli je goto v assembleru pouze instrukce JMP (a jeji vysledek ve strojovem kodu je vlastne take jenom skok na adresu), pak by melo goto teoreticky zkracovat strojovy kod, nez goto obchazet.
Ano, jedná se o jednu JMP instrukci (na ia32/x64, ale myslím, že na většině architektur to bude stejné).
Nemyslím, že by explicitní použití goto zdrojáky výrazně zkracovalo ve výše diskutovaných případech. Při vyskakování ze zanořeného cyklu ven vám ušetří pár podmínek (což obvykle je pár instrukcí).
Většinu kódu stejně netvoří skoky.
Co se týče té mojí ukázky, tam byste musel prostě místo goto volat ty finit funkce a pak dělat return. Nebo ten kód přepsat na něco jako:
err = a_init();
if (!err) {
err = b_init();
if (!err) {
err = c_init();
. . .
}
b_finit();
}
a_finit();
}
return err;
Tím se goto zbavíte, ale zase se tam přidává indentace, takže když těch init funkcí máte hodně, nedá se to číst ("ujíždí" to doprava). A někdo zase může preferovat ten způsob s goto.
Také nezapomeňte na to, že i když voláte ty finit funkce opakovaně, moc tím kód neprodulužujete, protože volání znamená jen pár instrukcí pro předání parametrů a instrukci CALL pro samotný skok na danou funkci.
Ta čitelnost je důležitá. Standardní konstrukty jako if, for, while, do-while, switch v sobě nějakou formu skoku mají ukrytou (podmíněnou či nepodmíněnou), ale vždy víte, kam se máte dívat, pokud třeba chcete vidět, co je za koncem cyklu (kudy to "vede" dál). Pokud budete používat goto a prostě skákat na různá návěští bez dodržování nějaké konvence, musíte si při čtení pamatovat, kde ta návěští jsou (a tak nějak si pamatovat ten graf možných skoků).
-
Tím se goto zbavíte, ale zase se tam přidává indentace, takže když těch init funkcí máte hodně, nedá se to číst ("ujíždí" to doprava). A někdo zase může preferovat ten způsob s goto.
Sice je to špatný příklad, kde by nemělo pro pár instrukcí smysl dělat nějakou optimalizaci...
Ale co je špatného na tomto:
err = a_init();
if (err) return err;
err = b_init();
if (err) return err;
err = c_init();
if (err) return err;
?
-
Tím se goto zbavíte, ale zase se tam přidává indentace, takže když těch init funkcí máte hodně, nedá se to číst ("ujíždí" to doprava). A někdo zase může preferovat ten způsob s goto.
Sice je to špatný příklad, kde by nemělo pro pár instrukcí smysl dělat nějakou optimalizaci...
Ale co je špatného na tomto:
err = a_init();
if (err) return err;
err = b_init();
if (err) return err;
err = c_init();
if (err) return err;
?
musíte testovat návratovou hodnotu funkce při každém volání. Goto zjednodušuje použití těch funkcí, kde může nastat chybový stav. Může vyskočit i z více úrovní volání.
-
Tam je problém, že v případě, kdy selže třeba b_init musí mít vyšší vrstva kódu na paměti, že by měla zavolat a_finit.
-
musíte testovat návratovou hodnotu funkce při každém volání. Goto zjednodušuje použití těch funkcí, kde může nastat chybový stav. Může vyskočit i z více úrovní volání.
Ano jistě, ale šlo mi spíš o to přímé return err, místo Goto Exit,
Tam je problém, že v případě, kdy selže třeba b_init musí mít vyšší vrstva kódu na paměti, že by měla zavolat a_finit.
Problém nevidím, může to ta vrstva poznat? O to v tom příkladu snad nešlo... Určitě by se to pak napsalo úplně jinak, ne?
-
Snad nikdy sem nevidel kod, kde by bylo GOTO nejak zneuzivano. IMO se cele GOTO trochu moc demonizuje. Pouziva se minimalne a kdyz uz, tak to na tom miste, kde se pouzilo, proste nevadi. Ucit deti, ze by GOTO nemely pouzivat asi nejaky smysl ma, ale obecne, kdyz nekdo zacne programovat a misto "BEGIN" a "END" si vybere GOTO, asi by se mel radeji venovat necemu jinemu.
-
musíte testovat návratovou hodnotu funkce při každém volání. Goto zjednodušuje použití těch funkcí, kde může nastat chybový stav. Může vyskočit i z více úrovní volání.
Ano jistě, ale šlo mi spíš o to přímé return err, místo Goto Exit,
myslel jsem, že se tu řeší, jak se takovým konstruktům vyhnout pomocí GOTO.
-
musíte testovat návratovou hodnotu funkce při každém volání. Goto zjednodušuje použití těch funkcí, kde může nastat chybový stav. Může vyskočit i z více úrovní volání.
Ano jistě, ale šlo mi spíš o to přímé return err, místo Goto Exit,
myslel jsem, že se tu řeší, jak se takovým konstruktům vyhnout pomocí GOTO.
Dobře, záleží, jestli hledáme argumenty pro použití goto, nebo proti.
-
musíte testovat návratovou hodnotu funkce při každém volání. Goto zjednodušuje použití těch funkcí, kde může nastat chybový stav. Může vyskočit i z více úrovní volání.
Ano jistě, ale šlo mi spíš o to přímé return err, místo Goto Exit,
To si můžete dovolit tam, kde nepotřebujete před návratem provést nějaký úklid. Samozřejmě jde použít i něco jako
ret = init_foo();
if (ret < 0) {
/* cleanup */
return ret;
}
ale v případech, o kterých se tu bavíme, bude toho úklidu přibývat, jak bude přibývat provedených inicializací.
Tam je problém, že v případě, kdy selže třeba b_init musí mít vyšší vrstva kódu na paměti, že by měla zavolat a_finit.
Problém nevidím, může to ta vrstva poznat? O to v tom příkladu snad nešlo... Určitě by se to pak napsalo úplně jinak, ne?
Zkuste se podívat třeba sem (https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/net/ipv6/af_inet6.c#n971) na funkci inet6_init() a rozmyslete si, jak by ten kód vypadal, kdybyste se chtěl za každou cenu vyhnout použití goto.
-
Problém nevidím, může to ta vrstva poznat? O to v tom příkladu snad nešlo... Určitě by se to pak napsalo úplně jinak, ne?
Já se snažím psát funkce tak, aby když selžou, vrátily stav programu do stavu před svým voláním (tzn. uklidí po sobě). Pokud tedy vynecháte některé z finit volání, tak máte pravděpodobně resource leak.
Samozřejmě, můžete si pamatovat , že "když funkce X selže, musím někde zavolat a_finit, protože ona to neudělala"; podle mě pak ale kód přestává být srozumitelný.
-
Problém nevidím, může to ta vrstva poznat? O to v tom příkladu snad nešlo... Určitě by se to pak napsalo úplně jinak, ne?
Já se snažím psát funkce tak, aby když selžou, vrátily stav programu do stavu před svým voláním (tzn. uklidí po sobě).
No to je důvod proč preferuji pure funkce. Protože vím že nemohou ovlivnit okolní stav jinak než je očekáváno (to znamená nijak).
-
Samozřejmě, můžete si pamatovat , že "když funkce X selže, musím někde zavolat a_finit, protože ona to neudělala"; podle mě pak ale kód přestává být srozumitelný.
Hlavně rychle přestane být udržovatelný. Bude potřeba pořád hlídat, jestli na to někdo nezapomněl. Když se bude volat na deseti místech, tak aby si na to člověk radši napsal wrapper - ale když tu funkci budu pokaždé volat přes (stejný) wrapper, tím spíš vynikne, že cleanup měl být rovnou v té funkci. A ani z logického hlediska to nedává smysl, pokud funkce něco alokuje, má to po návratu zůstat alokované jen v případě, že volající potřebuje, aby to alokované zůstalo.
Navíc jsme se tu bavili o případech, kdy těch inicializačních kroků je víc, selhat může kterýkoli z nich a volající obecně neví, který to byl a co je potřeba uklidit. Nemluvě o tom, že v praxi to často nebude jen prosté a_init() ... a_finit(), protože se úklidové funkci bude předávat pointer na to, co se má uklidit, který volající ani nebude mít k dispozici.
-
:D compilace/disassembling je docela dobry napad :)
Ale jak uz bylo receno, brani mi v tom znalost ASM. Mimochodem, taky bych chtel trochu ten ASM okusit.
https://godbolt.org/z/elNcJ8 (https://godbolt.org/z/elNcJ8) - to je dobry link, diky moc :)
To je škoda, by jste viděl, že to je prostě strojová instrukce jmp (skok na adresu) a že těch jmp je tam normálně víc. Jak píše Linus Torvalds: Každý if je goto.
Proto je lepsi se if-um vyhybat :-). Taky proto mozna vznikaji jazyky ktery maji polymorphic dispatch, pattern matching a podobne.... (a ano je to taky prevleceny goto... )
Podle me se to proste hur cte...
Kompiler at si tam naseka jmp kolik chce.... ale proc to mam cist ja?
A jeste sem tu nevidel link na https://homepages.cwi.nl/~storm/teaching/reader/Dijkstra68.pdf (https://homepages.cwi.nl/~storm/teaching/reader/Dijkstra68.pdf)
Jo jasne, je lepsi se vyhybat ifum, ale pattern matching je cesta... haha, tak ty jsi to rozsekl frajere...
Co je spatneho na pattern matching?
Za mne vubec nic, ale ja taky neplivu na ify. Mi prijde vtipne, ze plives na obecne vyhodnocovani podminky, ale vyhodnocovani konkretni podminky a to konkretne pattern matchingu ti prijde v poradku.
-
Tím se goto zbavíte, ale zase se tam přidává indentace, takže když těch init funkcí máte hodně, nedá se to číst ("ujíždí" to doprava). A někdo zase může preferovat ten způsob s goto.
Sice je to špatný příklad, kde by nemělo pro pár instrukcí smysl dělat nějakou optimalizaci...
Ale co je špatného na tomto:
err = a_init();
if (err) return err;
err = b_init();
if (err) return err;
err = c_init();
if (err) return err;
?
Kde a jak zavolate a_finit(), b_finit(), atd. ?
-
Problém nevidím, může to ta vrstva poznat? O to v tom příkladu snad nešlo... Určitě by se to pak napsalo úplně jinak, ne?
Já se snažím psát funkce tak, aby když selžou, vrátily stav programu do stavu před svým voláním (tzn. uklidí po sobě).
No to je důvod proč preferuji pure funkce. Protože vím že nemohou ovlivnit okolní stav jinak než je očekáváno (to znamená nijak).
Můžou měnit kontext.
-
Nejznámější variantou goto je switch-case. Jinak v C++ je to složitější když v rámci skoku preskakuju inicializaci objektů - není to fakt dobrý nápad a týká se to i switch case. Naštěstí překladač to oznámí. Takže je fakt dobré sahat na goto až je to opravdu nutné
Pokud při skoku opouštím blok kde končí platnost některých proměnných, zavolají se destruktory - takže obyčejný JMP to není.
(Právě kvůli finalizaci mám rád koncept RAII - pak goto nepotřebuju)
-
> povazuje prekladac zmineny blok kodu (ze ktereho jsem vyskocil) za ukonceny?
Co to pro vás znamená? Pokud vyskočíte ze scope, tak jste vyskočil ze scope. A pokud nepoužíváte nějaké GNU extensions jako je __attribute__((cleanup(...))), tak opuštění scope v C nic moc neznamená.
-
Citoval bych tady úryvek z knihy Modern C (https://modernc.gforge.inria.fr/) k použití goto pro error handling:
The use of goto and similar jumps in programming languages has been subject to intensive debate, starting from an article by Dijkstra [1968]. You will still find people who seriously object to code as it is given here, but let us try to be pragmatic about that: code with or without goto can be ugly and hard to follow. The main idea is to have the “normal” control flow of the function be mainly undisturbed and to clearly mark changes to the control flow that only occur under exceptional circumstances with a goto or return.
Na straně 240-249 je pak o něco komplikovanější příklad, kde použití goto dává smysl...
-
No to je důvod proč preferuji pure funkce. Protože vím že nemohou ovlivnit okolní stav jinak než je očekáváno (to znamená nijak).
Můžou měnit kontext.
Můžeš to rozvést?
-
No to je důvod proč preferuji pure funkce. Protože vím že nemohou ovlivnit okolní stav jinak než je očekáváno (to znamená nijak).
Můžou měnit kontext.
Můžeš to rozvést?
To byla jen poznámka na okraj, že i pure funkce můžou efektivně měnit okolní kontext, když je typový systém dostatečně silný, záleží na tom, jak se řetězí. Celé FP je postavené na tom, že funkce jsou sice pure (což je omezení), ale typový systém je natolik silný, že lze v případě nutnosti měnit vnější kontext, čímž se ono “omezení” kompenzuje.