Autor Wątek: UB & goto  (Przeczytany 7313 razy)

Offline Xender

  • Użytkownik

# Sierpień 07, 2014, 18:31:22
// wydzielone z wątku "Twój najgłupszy błąd"

Ja je interpretuję tak, że "zagadki powinny dotyczyć specyfikacji języka, a nie konkretnych implementacji", tzn. pytania o wynik undefined behavior, implementation-defined behavior, czy jawne odstępstwa od standardu np. w celu optymalizacji się nie kwalifikują.
Nie psuj zabawy, zwłaszcza, że zabawa jest edukacyjna.

Zachowania konkretnych implementacji w obliczu UB są równie ważne, co standard. Nie da się rozpatrywać ich osobno.
« Ostatnia zmiana: Sierpień 09, 2014, 19:51:47 wysłana przez Xion »

Offline Mr. Spam

  • Miłośnik przetworów mięsnych

Offline Xirdus

  • Redaktor

# Sierpień 07, 2014, 18:48:36
Zachowania konkretnych implementacji w obliczu UB są równie ważne, co standard. Nie da się rozpatrywać ich osobno.
Ja tam wolę nigdy na żadnym UB nie polegać - traktować je jako cichy fatal error.

Offline Xender

  • Użytkownik

# Sierpień 07, 2014, 18:57:40
A kto powiedział o poleganiu na UB?

Tylko spróbuj wyjaśnij komuś, kto nie wie, co to UB, czemu ma ich unikać. Czemu nie powinien pisać:
i = i++ + j;
Spróbuj wyjaśnić to, nie odwołując się do konkretnych implementacji kompilatorów, a jedynie mówiąc o standardzie. Bez konkretnego przykładu, że np. "G++ i VC++ na różnych poziomach optymalizacji potraktują to inaczej" masz średnie szanse przebicia się przez "ale u mnie to działa".

Offline Xirdus

  • Redaktor

  • +2
# Sierpień 07, 2014, 19:05:31
Spróbuj wyjaśnić to, nie odwołując się do konkretnych implementacji kompilatorów, a jedynie mówiąc o standardzie. Bez konkretnego przykładu, że np. "G++ i VC++ na różnych poziomach optymalizacji potraktują to inaczej" masz średnie szanse przebicia się przez "ale u mnie to działa".
Z drugiej strony, jeśli będzie wiedział jaki jest dany rezultat w danym kompilatorze przy danej konfiguracji, to może stwierdzić, że łatwiej jest związać się na wieczność z jednym kompilatorem i nigdy nie zmieniać konfiguracji, i dalej pisać w tym stylu. Dzięki temu, że ktoś kiedyś wymyślił, że goto jest złe i kropka, nie musimy się dziś przedzierać przez setki goto szukając błędu.

Offline revo

  • Użytkownik

# Sierpień 07, 2014, 21:59:39
Tylko spróbuj wyjaśnij komuś, kto nie wie, co to UB, czemu ma ich unikać. Czemu nie powinien pisać:
i = i++ + j;
Spróbuj wyjaśnić to, nie odwołując się do konkretnych implementacji kompilatorów, a jedynie mówiąc o standardzie.

Jeżeli ktoś jest na etapie, że tego nie rozumie, samo wspomnienie o sequence points powinno skutecznie zamknąć mu usta ;)

Offline Xender

  • Użytkownik

  • +2
# Sierpień 09, 2014, 16:29:17
Dzięki temu, że ktoś kiedyś wymyślił, że goto jest złe i kropka, nie musimy się dziś przedzierać przez setki goto szukając błędu.
:D

Goto nie ma nic do rzeczy, a nadal istnieje dlatego, że nie każdy dał sobie wyprać mózg tym jednym argumentem.

Argument jest w porządku, ale tylko w tutorialach i książkach dla początkujących. Jak traktujesz swojego rozmówcę serio, to już nie przejdzie.

Przy czym moim chyba ulubionym przykładem jest, jak p. Grębosz w "Pasji C++" na fali "goto jest złe" proponował wychodzenie z zagnieżdżonych pętli (szukanie elementu w tablicy tablic) poprzez użycie wyjątków.
I to dopiero jest porażka z flow control. Ot, do czego prowadzi bezmyślnie powtarzana "mantra".

Offline Paweł

  • Użytkownik

# Sierpień 09, 2014, 16:44:47
Ciekaw jestem reakcji moich/waszych kolegów  z pracy na takie wyjście z pętli z użyciem goto. Sam do tego nic nie mam, ale zakładam że znajdzie się paru "Xirdusów" twierdzących że goto jest nieprofesjonalne i w ogóle wstyd.

Offline revo

  • Użytkownik

# Sierpień 09, 2014, 16:53:38
Może ktoś by wyciął dyskusję o goto do osobnego wątku? ;)

Tymczasem do poczytania: Go To Statement Considered Harmful

Offline Xirdus

  • Redaktor

  • +1
# Sierpień 09, 2014, 18:08:43
Argument jest w porządku, ale tylko w tutorialach i książkach dla początkujących.
Mówiliśmy o kimś, kto nie wie co to undefined behavior i dlaczego jest złe - czyli o początkującym.

Goto nie ma nic do rzeczy, a nadal istnieje dlatego, że nie każdy dał sobie wyprać mózg tym jednym argumentem.
Istnieje dlatego, że jest w niektórych sytuacjach niezbędne - bo językowi brakuje innych mechanizmów do np. podwójnego breaka - oraz dla kompatybilności wstecznej.

Przy czym moim chyba ulubionym przykładem jest, jak p. Grębosz w "Pasji C++" na fali "goto jest złe" proponował wychodzenie z zagnieżdżonych pętli (szukanie elementu w tablicy tablic) poprzez użycie wyjątków.
I to dopiero jest porażka z flow control. Ot, do czego prowadzi bezmyślnie powtarzana "mantra".
Świadczy to tylko o tym, że wyjątki są jeszcze gorsze. Gdybym mógł cofnąć się w czasie, poprosiłbym Dijkstrę o napisanie artykułu "Exceptions considered harmful" - po to, by ludzie nie umiejący ich używać ich nie używali.

BTW jak dla mnie, najlepszym sposobem sposobem poradzenia sobie z powyższym problemem w C++ jest wydzielenie zewnętrznej pętli do nowej funkcji i użycie returna. Z lambdami nawet nie wychodzi dużo więcej kodu.

Ciekaw jestem reakcji moich/waszych kolegów  z pracy na takie wyjście z pętli z użyciem goto. Sam do tego nic nie mam, ale zakładam że znajdzie się paru "Xirdusów" twierdzących że goto jest nieprofesjonalne i w ogóle wstyd.
Zauważ, że ja nigdzie nie powiedziałem, że goto jest nieprofesjonalne. Jak ktoś korzysta z niego mądrze, nie ma do czego się przyczepić - tak samo jak wykorzystywanie fall-through switcha. Problem w tym, że spora część programistów nie potrafi, szczególnie początkujących. Tak samo nie potrafią korzystać z dziedziczenia, makr itp.

Tymczasem do poczytania: Go To Statement Considered Harmful
"GOTO considered harmful" considered harmful ;)

Offline Xion

  • Moderator
    • xion.log

  • +2
# Sierpień 09, 2014, 19:59:39
Cytuj
Może ktoś by wyciął dyskusję o goto do osobnego wątku? ;)
Zrobione. Nawet zostawiłem w starym posta z linkiem do obecnego -- co działa jak, nie przymierzając, goto :)

Cytuj
BTW jak dla mnie, najlepszym sposobem sposobem poradzenia sobie z powyższym problemem w C++ jest wydzielenie zewnętrznej pętli do nowej funkcji i użycie returna.
Powiedziałbym, że to wręcz oczywiste.

Cytuj
Jak ktoś korzysta z niego mądrze, nie ma do czego się przyczepić - tak samo jak wykorzystywanie fall-through switcha.
Na palcach jednej ręki mogę policzyć przypadki, gdzie widziałem, że:
  • zastosowano fallthrough switch; oraz
  • między oboma case'ami była chociaż jedna instrukcja
We wszystkich pozostałych przypadkach językowi brakowało po prostu wielokrotnego case'a / pattern matchingu. (Co oczywiście nie sprawia, że fallthrough switch różni się pod tym względnem od goto -- wręcz przeciwnie).

Cytuj
"GOTO considered harmful" considered harmful ;)
Mam nadzieję, że ten ";)" wyraża twój stosunek do artykułu, bo rzadko widzi się bzdury podobnego ciężaru gatunkowego :)

Offline Xirdus

  • Redaktor

# Sierpień 09, 2014, 21:37:55
Mam nadzieję, że ten ";)" wyraża twój stosunek do artykułu, bo rzadko widzi się bzdury podobnego ciężaru gatunkowego :)
Jak wolisz, to jest jeszcze artykuł "\"\\\"GOTO Considered Harmful\\\" Considered Harmful\" Considered Harmful" - jednak nie mogę go teraz nigdzie znaleźć. Osobiście uważam, że goto jest złe nie dlatego, że prowadzi do fatalnego kodu, tylko pozwala na tworzenie fatalnego kodu - co w niewłaściwych rękach jest zgubne.

Offline Xender

  • Użytkownik

# Sierpień 10, 2014, 23:17:24
Osobiście uważam, że goto jest złe nie dlatego, że prowadzi do fatalnego kodu, tylko pozwala na tworzenie fatalnego kodu - co w niewłaściwych rękach jest zgubne.
I tu dochodzimy do kwestii chronienia programisty przez nim samym, poprzez wycinanie "potencjalnie niebezpiecznych" elementów z języka.

Nie jestem zbytnim sympatykiem takiego podejścia, chociaż ma ono swoje zastosowanie. Zważ jednak na dwie rzeczy:
- Niewprawny programista nadal będzie pisał kod kiepski, tyle, że pod innymi względami. Ograniczanie niebezpiecznych operacji może tu nieco pomóc, ale nie jest to żadne panaceum.
- Pomijając nawet argument kompatybilności wstecznej - to, że coś jest niepotrzebne w 99.99% przypadków, nie znaczy, że jest niepotrzebne w ogóle. Znaczy tylko tyle, że te 1/10'000 przypadków nadal trzeba jakoś obsłużyć.

Mam więc nadzieję, iż zdajesz sobie sprawę, że nie jest możliwe wyeliminowanie goto (ani innych potencjalnie niebezpiecznych/niepożądanych operacji) ze wszystkich języków programowania.
Zawsze będzie potrzebny język, który będzie ostoją dla:
- przypadków brzegowych,
- programistów, którzy wiedzą, co robią,
- programistów, którym tylko się wydaje, że wiedzą, co robią,
- wszelkiego rodzaju operacji niskopoziomowych.

Tymi językami są obecnie C i C++.

Offline Xirdus

  • Redaktor

# Sierpień 10, 2014, 23:43:32
Mam więc nadzieję, iż zdajesz sobie sprawę, że nie jest możliwe wyeliminowanie goto (ani innych potencjalnie niebezpiecznych/niepożądanych operacji) ze wszystkich języków programowania.
Jest. Wystarczy zastąpić je innymi konstrukcjami pozwalającymi na to samo, ale w bezpieczniejszy sposób - np. w przypadku wielokrotnego breaka, etykiety pętli. Pozostałe use case'y goto da się zastąpić pętlami albo wydzielaniem funkcji i early returnami. O czymś zapomniałem?

Zawsze będzie potrzebny język, który będzie ostoją dla:
- przypadków brzegowych,
- programistów, którzy wiedzą, co robią,
- programistów, którym tylko się wydaje, że wiedzą, co robią,
- wszelkiego rodzaju operacji niskopoziomowych.

Tymi językami są obecnie C i C++.
Poza trzecim myślnikiem, zgadzam się w zupełności - ale dlaczego niby ten język będący ostoją powyższych musi mieć jak najbardziej ułatwiać strzelanie sobie w stopę? Dlaczego nie ograniczyć swobody programisty w imię stabilności kodu, pozostawiając jednak możliwość operowania na dowolnie niskim poziomie?

Offline Xender

  • Użytkownik

  • +1
# Sierpień 11, 2014, 19:30:48
Dlaczego nie ograniczyć swobody programisty
Bo punkty 1, 2 i 3.

To, że nie widzisz przypadku użycia goto, który dałby się zastąpić czymś innym, nie znaczy, że takiego nie ma.
Więc dopóki nie jesteś wyjadaczem C/C++ z "brodą" (lub członkiem komitetu standaryzacyjnego, co jest skorelowane), to nie masz co myśleć o zmienianiu standardu po swojemu, bo zawsze coś przeoczysz. To punkt 1.

Niektórzy nie lubią, nawet bardzo nie lubią, jak ktoś chce im ograniczać swobodę w imię czegoś, co uważa za ważniejsze. To punkty 2 i 3.

Offline Xirdus

  • Redaktor

# Sierpień 11, 2014, 19:53:36
Dlaczego nie ograniczyć swobody programisty
Bo punkty 1, 2 i 3.
Ale drugiej części to już nie raczyłeś przeczytać?

To, że nie widzisz przypadku użycia goto, który dałby się zastąpić czymś innym, nie znaczy, że takiego nie ma.
Ale póki ktoś mi nie pokaże takiego przypadku, będę twierdził, że więcej z goto szkody niż pożytku, i że dobrze że nowoczesne języki programowania go nie mają.

Więc dopóki nie jesteś wyjadaczem C/C++ z "brodą" (lub członkiem komitetu standaryzacyjnego, co jest skorelowane), to nie masz co myśleć o zmienianiu standardu po swojemu, bo zawsze coś przeoczysz. To punkt 1.
Standardy mają to do siebie, że można je zmieniać. Twórcy Javy przeoczyli lambdy i dodali je w wersji 8. Jednocześnie dalej nie ma tam goto - widocznie nie jest potrzebne. Jak bym tworzył swój niskopoziomowy język, nie wrzuciłbym tam goto - ale tylko do czasu aż ktoś mi pokaże że umożliwia on rzeczy inaczej niemożliwe.

Wychodzenie z zagnieżdżonych pętli poprzez goto w C porównałbym do tworzenia symlinków w celu ustawienia strefy czasowej w Linuksie - i goto, i symlinki pozwalają na bardzo wiele trików, więc twórcy odpowiednio C i Linuksa nie wprowadzają żadnych zamienników, bo obecne narzędzia mimo, że sto razy gorsze, i bardzo łatwo o błąd, to jednak spełniają swoje zadanie.

// część o Linuksie przenosłem do http://forum.warsztat.gd/index.php?topic=29176.0 -Xirdus
« Ostatnia zmiana: Sierpień 12, 2014, 19:01:03 wysłana przez Xirdus »