Czy i, j = 1 naprawdę wprowadza w błąd? [Zamknięte]

11

Istnieje wspólny argument na temat inicjalizacji wielu zmiennych w jednym wkładce, to znaczy:

Rozważmy na przykład int i, j = 1; co może doprowadzić niektórych ludzi do błędnego przekonania, że ​​obie zmienne są inicjalizowane

Możemy argumentować, że ktoś powinien znać składnię swojego języka na tyle, żeby się nie mylić. Kolejnym argumentem może być to, że programiści uczą się tak wielu języków, że możemy popełniać błędy między specyfikami między językami.

Jednak w tym konkretnym przypadku zastanawiam się, czy istnieje nawet język, w którym sama składnia i, j = 1 inicjuje obie zmienne?

Jeśli nie, ten argument nie ma zastosowania.

Walfrat
źródło
2
Jeśli twój język jest rozsądny, potencjalne zamieszanie jest nieszkodliwe, ponieważ dostęp do niezainicjowanej zmiennej powoduje błąd kompilatora.
CodesInChaos
4
@CodesInChaos, czy mówisz, że C nie jest normalny?
Baldrickk
2
To, że język na coś pozwala, nie oznacza, że ​​nie powodujesz niepotrzebnego bólu. Jedynym miejscem, do którego ten kod jest wymagany, są quizy mające na celu ukaranie tych, którzy nie zapamiętali specyfikacji języka. Zawsze nie odpowiadałem na tego typu pytania. Bleh
candied_orange
2
W Visual Basic 6 Dim Apple, Orange, Pear as Fruitjest deklaracja prawna. Załóżmy, że nie znasz VB. Czy twoje pierwsze wrażenie Applejest tego rodzaju Fruit? Nie jest. Pamiętaj, że języki często czytają ludzie, którzy nie są ekspertami w tym języku; jeśli jesteś ekspertem, mądrze posługuj się językiem, aby jasno przekazać swoje zamiary nawet osobom niebędącym ekspertami. Nigdy nie używam wielu inicjalizacji w żadnym języku.
Eric Lippert,
13
Podobnie: rozważ var x = 1, y = 1.5; Czy to jest to samo, int x = 1; double y = 1.5;czy to to samo, co double x = 1, y = 1.5;? Kiedy dodaliśmy vardo C # 3.0, zrobiłem ankietę i odkryłem, że około połowa ludzi uważa, że ​​pierwsza jest „oczywiście” poprawna, a druga połowa uważa, że ​​druga jest „oczywiście” poprawna, dlatego też zrobiliśmy to nielegalnym. Funkcja, która wprowadza w błąd połowę populacji, jest złą cechą.
Eric Lippert,

Odpowiedzi:

37

Myślę, że nie, ale nie o to chodzi. Chodzi o to, że i, j = 0jest bardzo łatwo pomylić i = j = 0, co robi initialize obu. Klarowność jest najważniejszym wymogiem dotyczącym kodu źródłowego obok poprawności, a fakt, że to pytanie nawet powstaje, dowodzi, że klarowność jest nieoptymalna.

Kilian Foth
źródło
3
Twierdziłbym również, że jeśli takie oświadczenie nie inicjuje obu oświadczeń, dlaczego w ogóle istnieje?
Berin Loritsch
2
@BerinLoritsch zależy od języka. Jest to często wykonywane w JavaScript ze względu na podnoszenie deklaracji: wielu uważa za najlepszą praktykę deklarowanie zmiennych u góry zakresu, w którym są one dostępne, nawet jeśli nie zainicjujesz ich, dopóki nie zostaną użyte w kodzie . Prawie wszystkie narzędzia do przekształcania kodu są generowane w ten sposób.
Jared Smith
1
Przypuszczam, że to jedno, jeśli narzędzie wyjściowe kodu to zrobiło, ponieważ należy temu ufać. Jednak dla ludzi odradzałbym łączenie deklaracji i inicjalizacji ostatniego elementu tylko w jednym wierszu. Wygląda to jak błąd, który czeka.
Berin Loritsch
2
@JaredSmith Oprócz Maple, nie mogę wymyślić języka, w którym jest to obecnie pożądane, nawet C woli teraz bliżej zakresu (jak C ++ i większość innych języków z pół przyzwoitymi kompilatorami statycznymi), ponieważ daje to korzyści z zatrzymania potencjalnych błędów i pozwala kompilator, aby zdecydować, co zrobić ze zmienną, dopóki funkcjonalność się nie zmieni, potencjalnie umożliwiając lepsze optymalizacje, biorąc pod uwagę, że można uniknąć mniejszej liczby rejestrów.
kiedy
6
Niezależnie od języka należy zapytać: „Jaka jest korzyść z pisania w int i, j=1porównaniu z int i; int j = 1(a nawet lepiej, osobnymi wierszami)?”
chepner
2

Myślę, że możesz argumentować za którąkolwiek ze stron:

  • Kontra i, j = 0:
    Matematycy zrobić to wykorzystać, aby oznaczać, że zarówno ii jmają być zero.

  • Pro i, j = 0:
    Prostą sprawą jest znajomość pierwszeństwa swoich operatorów. A jeśli masz wątpliwości co do ich pierwszeństwa, nadszedł czas, aby to sprawdzić.

    To ten sam powód, dla którego piszemy rzeczy a.b += c[i]*d[i];bez nawiasów. Oczywiście jest to równoważne (a.b) += ((c[i])*(d[i]));, ale można się spodziewać, że programiści znają na pamięć pierwszeństwo najczęściej używanych operatorów i są w stanie sprawdzić pierwszeństwo operatorów, gdy nie są pewni. Tak więc nawiasy są ogólnie uważane za bezużyteczne, jeśli nie wymuszają innej kolejności oceny, niż nakazałaby pierwszeństwo operatora.

    Oczywiście, istnieją wyjątki. Pierwszeństwo <<i +jest ogólnie uważane za wystarczająco dwuznaczne, aby uzasadnić nawiasy w obu przypadkach. Ale to wyjątek potwierdzający regułę.

Ja, na przykład, wpadłbym bardziej na stronę Pro, ale jestem gotowy trzymać się każdego przewodnika po stylach, który zabrania takich deklaracji. To po prostu nie jest warte walki.

cmaster - przywróć monikę
źródło
7
Zauważam, że int i, j = 0;nie ma w nim operatorów . Jedynym wyrażeniem w tym stwierdzeniu jest, 0dlatego też nie ma w nim pierwszeństwa operatorów . Analizator składni nie jest traktowany ,jako operator przecinka ani =operator przypisania; są to raczej gramatyczne części oświadczenia.
Eric Lippert,
@EricLippert Jeśli chodzi o reguły pierwszeństwa, różnica ta jest nieistotna: każdy język w stylu C, który znam, używa takich samych pierwszeństw w deklaracji, jak w innych wyrażeniach. Cokolwiek innego zaprosiłoby katastrofę.
cmaster
but programmers can be expected to know the precedence of the most used operators by heart, mówisz. W podanym przez ciebie przykładzie nie jestem pewien, czy większość (przeciętnych) programistów postrzega operatora dostępu do elementu lub operatora indeksu tablic jako operatorów w sensie matematycznym, ale zamiast tego traktuje je bardziej jako rzeczowniki języka naturalnego i mnożenie operator jako czasownik. Właśnie dlatego int i, j, k = 0;jest tak diabelskim konstruktem, ponieważ przedstawia jako naturalny język analog „int zmiennych i, j i k, są zadeklarowane i powinny być ustawione na 0”!
Steve
@ Steve To, jak pamiętasz zasady pierwszeństwa jako programisty, zależy wyłącznie od Ciebie. Jeśli pomaga ci myśleć o nich jak o rzeczownikach języka, zrób to. Jednak w takim przypadku napotkasz problemy, gdy zobaczysz coś takiego *a[i], nie sądzę, że możesz wystarczająco przeanalizować to za pomocą analogii „rzeczowników”. Co do int i, j, k = 0;tego, może to znaczyć wszystko, jeśli nie spojrzysz na reguły: Trzecią interpretacją byłoby zadeklarowanie int i, następnie ocena ji ostatecznie przypisanie k = 0. Jeśli nie znasz składni swojego języka, nie możesz analizować takich konstrukcji. W każdym razie to twój problem.
cmaster
@cmaster, nie wyraziłem mojej konkretnej strategii zapamiętywania haha. Nie jestem programistą C, więc moja znajomość pierwszeństwa operatorów w C jest drugorzędna. Ale, kiedy zauważyłem twój przykład, zauważyłem, że nawet nie myślałem, że operator mnożenia ma względne pierwszeństwo przed operatorem indeksu tablicowego. To znaczy, nie czytałem a[i]jako zastosowanego operatora indeksu a, ale raczej czytałem oba razem jako nieredukowalny element składniowy określający operand operatora mnożenia, a zatem nie byłem nawet proszony o ocenę pierwszeństwa. (1/2)
Steve