Czy kiedykolwiek jest możliwe, aby warunek miał skutki uboczne? [Zamknięte]

10

Biorę kurs pośrednich struktur danych jako warunek wstępny do programu CS MS na uniwersytecie, o którym wszyscy w Ameryce słyszeli. Jeden wiersz kodu, który został napisany w klasie, przykuł moją uwagę:

if (a > 33 | b++ < 54) {...}

To nie przejdzie przeglądu kodu w moim miejscu pracy. Gdybyś napisał taki kod w wywiadzie, byłby to znaczący atak przeciwko tobie. (Oprócz bycia warunkowym z efektami ubocznymi, jest sprytny kosztem przejrzystości).

W rzeczywistości nigdy nie widziałem warunku z efektami ubocznymi, a Googling też się nie pojawia. Kolejny uczeń został też po zajęciach, żeby o to zapytać, więc nie jestem jedynym, który uważał to za dziwne. Ale profesor był zdecydowanie nieugięty, że był to akceptowalny kod i że napisałby coś takiego w pracy. (Jego praca FT jest jako główny SWE w firmie, o której wszyscy słyszeliście.)

Nie wyobrażam sobie świata, w którym ten wiersz kodu byłby kiedykolwiek akceptowalny, a tym bardziej pożądany. Czy się mylę? Czy to jest ok? Co z bardziej ogólnym przypadkiem: warunki warunkowe z efektami ubocznymi? Czy to jest w porządku?

rianjs
źródło
7
Ta linia powinna być nukowana z orbity. Dwa razy dla dobrego wyniku.
Blrfl,
8
Nit: Pojedyncza rura (pionowy pasek) jest nieco bitowa lub w większości języków, a nie logiczna „lub”. Nie powoduje zwarcia, jeśli lewa strona jest prawdziwa. Ponieważ ten warunek ma skutki uboczne po prawej stronie, robi to szczególnie dużą różnicę w wyniku.
Jonathan Eunice,
2
Istnieją idiomy używane w różnych językach, które należałyby do tej kategorii, ale ponieważ są „dobrze znane” lub „normalne”, nie powodują problemów. Linia w pytaniu nie wydaje się należeć do kategorii stosowania idiomatycznego, więc bym tego unikał.
Jaydee,
2
@JonathanEunice, tak, niektórzy ludzie byli zdezorientowani oceną zwarcia. Z mojej strony nie literówka.
rianjs
5
Spójrz na to z dobrej strony. Teraz znasz jeszcze jedną firmę, w której NIE chcesz rozmawiać.
John R. Strohm,

Odpowiedzi:

23

Jest jeden pół-warunkowy efekt uboczny, o którym myślę, że jest w porządku:while(iter.MoveNext())

To powiedziawszy, myślę, że należy to głównie do kategorii „ nigdy nie jest naprawdę wielkim kwalifikatorem”. Mogę wymyślić kilka rzadkich przypadków, w których widziałem, że jest to akceptowalne, ale ogólnie jest to podłe i należy tego unikać.

Nie mogę również wymyślić scenariusza, w którym ta konkretna linia byłaby do zaakceptowania, ale nie mogę również wymyślić scenariusza, w którym ta konkretna linia byłaby przydatna , więc trudno jest wyobrazić sobie kontekst, w którym się znajduje.

Telastyn
źródło
To była po prostu kwestia odrzucenia metody podczas zajęć. Nie miało to na celu zrobienia niczego pożytecznego.
rianjs
4
Równolegle, while(v = *p++)skanowanie w stylu C / C ++ poprzez tablicę zakończoną zerem (np. Łańcuch C) jest dość powszechne i powszechnie akceptowane.
Phil Miller,
3
Często uważałem pętlowe warunki warunkowe tej formy while(c = input.read() != '\n')za dość idiomatyczne.
1
Może istnieć kilka powszechnie akceptowanych idiomów, ale wyraźnie „bycie sprytnym kosztem przejrzystości” przypada na obóz NIGDY.
Julia Hayward,
Całkowicie zapomniałem o iter.MoveNext (). Całkowicie uzasadniony przypadek warunku mającego efekt uboczny. Dzięki!
rianjs
8

W moim świecie odczyt z pamięci można uznać za efekt uboczny (np. IO zmapowane w pamięci).

Teraz rozważ następujące kwestie:

    while( ( *memory_mapped_device_status_register & READY_FLAG) == 0) {
       // Wait
    }

I porównaj do:

    status = *memory_mapped_device_status_register;
    while( ( status & READY_FLAG) == 0) {
        // Wait
        status = *memory_mapped_device_status_register;
    }

Czy uniknięcie efektu ubocznego (odczyt) w tym stanie pomogło w czytelności; czy po prostu zduplikował kod i dodał bałaganu?

Nie jest dozwolone, aby warunek miał skutki uboczne (jeśli to sprawia, że ​​kod jest mniej czytelny), a także warunek może mieć skutki uboczne (jeśli to sprawia, że ​​kod jest bardziej czytelny). Kluczowym czynnikiem jest „czytelność”. Cała reszta to reguły tworzone przez głupców w nieudanej próbie poprawy czytelności (choć często mają odwrotny skutek).

Brendan
źródło
3

Jak zawsze w przypadku takich pytań, jest to kwestia stopnia. Gdyby istniał jednoznaczny dowód, że jakikolwiek efekt uboczny w ifwyrażeniu zawsze prowadzi do gorszego kodu, tworzenie takich wyrażeń byłoby niezgodne z prawem. Projektanci języków mogą być ideosynratycznymi, omylnymi ludźmi, ale nie są aż tak głupi.

To powiedziawszy, jakie są przykłady uzasadnionych skutków ubocznych w obrębie if? Załóżmy na przykład, że jesteś prawnie zobowiązany do rejestrowania całego i dowolnego dostępu do nieruchomości Pjednostki Edo celów audytu. (Wyobraź sobie, że pracujesz w zakładzie wzbogacania uranu, i istnieją bardzo ścisłe prawne kontrole tego, co twój kod może robić i jak powinien to robić.) W iftakim razie sprawdzenie, czy ta właściwość spowoduje efekt uboczny dziennik kontroli jest rozszerzany.

Jest to dość wyraźna kwestia przekrojowa, nie wpływa ona na twoje rozumowanie na temat stanu programu (bardzo), i możesz go wdrożyć, aby był całkowicie niewidoczny i nie rozpraszał, gdy przeglądasz linię za pomocą if(ukryty w akcesorium, a jeszcze lepiej przez AOP). Powiedziałbym, że to całkiem wyraźny przypadek efektu ubocznego, który nie stanowi problemu. Podobne sytuacje można sobie wyobrazić, gdy po prostu chcesz policzyć wykonania gałęzi do celów profilowania itp.

Im bardziej te okoliczności łagodzące znikną, tym bardziej obcy stanie się konstrukt. Jeśli określony typ pętli (np. if((c = getc()) == 'x') { quit(); }Jest dobrze znany i akceptowany przez społeczność językową, oznacza to o wiele mniejszy problem niż wtedy, gdy wymyślisz go spontanicznie itp. Twój przykładowy wiersz nie spełnia tego standardu, ale mógłbym sobie wyobrazić dużo, dużo bardziej okropne, których nawet nie będę pisać, są takie okropne.

Kilian Foth
źródło
2

Chociaż naprawdę śmierdzący kod, ma tę zaletę, że jest prostszy (i być może szybszy, jeśli nie masz dobrego kompilatora optymalizującego) niż jego odpowiednik if (a > 33 | b < 54) {b++; ...} else b++;

ale oczywiście można zoptymalizować go w następujący sposób (ale uważaj! ten ma inne zachowanie w przypadku przepełnienia!): b++; if (a > 33 | b < 53) {...}

Franki
źródło