Oprócz wszystkich wspaniałych dotychczasowych odpowiedzi:
Masz „uprzedzenie obserwatora”. Nie obserwujesz błędów i dlatego zakładasz, że ich nie ma.
Myślałem tak jak ty. Potem zacząłem pisać kompilatory profesjonalnie i powiem ci, że jest tam wiele błędów!
Nie widzisz błędów, ponieważ piszesz kod, który jest jak 99,999% całej reszty kodu, który ludzie piszą. Prawdopodobnie piszesz całkowicie normalny, prosty, wyraźnie poprawny kod, który wywołuje metody i uruchamia pętle i nie robi nic szczególnego ani dziwnego, ponieważ jesteś normalnym programistą rozwiązującym normalne problemy biznesowe.
Nie widzisz żadnych błędów kompilatora, ponieważ błędów kompilatora nie ma w łatwych do analizy, prostych, normalnych scenariuszach kodu; błędy dotyczą analizy dziwnego kodu, którego nie piszesz.
Z drugiej strony mam przeciwne nastawienie obserwatora. Cały dzień widzę szalony kod, więc dla mnie kompilatory wydają się być pełne błędów.
Jeśli usiądziesz ze specyfikacją języka dowolnego języka i weźmiesz jakąkolwiek implementację kompilatora dla tego języka i naprawdę spróbujesz ustalić, czy kompilator dokładnie zaimplementował specyfikację, czy nie, koncentrując się na niejasnych narożnych przypadkach, już wkrótce znajdziesz błędy kompilatora dość często. Dam ci przykład, oto błąd kompilatora C #, który dosłownie znalazłem pięć minut temu.
static void N(ref int x){}
...
N(ref 123);
Kompilator podaje trzy błędy.
- Argument ref lub out musi być zmienną, którą można przypisać.
- Najlepsze dopasowanie dla N (ref int x) zawiera nieprawidłowe argumenty.
- Brak „ref” w argumencie 1.
Oczywiście pierwszy komunikat o błędzie jest poprawny, a trzeci błąd. Algorytm generowania błędów próbuje dowiedzieć się, dlaczego pierwszy argument był nieprawidłowy, patrzy na niego, widzi, że jest stałą i nie wraca do kodu źródłowego, aby sprawdzić, czy został oznaczony jako „ref”; raczej zakłada, że nikt nie byłby na tyle głupi, aby oznaczyć stałą jako ref, i decyduje, że ref musi być pominięty.
Nie jest jasne, jaki jest prawidłowy trzeci komunikat o błędzie, ale to nie jest to. W rzeczywistości nie jest jasne, czy drugi komunikat o błędzie jest poprawny. Czy rozwiązanie przeciążenia powinno zawieść, czy też „ref 123” powinno być traktowane jako argument ref odpowiedniego typu? Muszę teraz przemyśleć i omówić to z zespołem zajmującym się segregacją, abyśmy mogli ustalić, jakie jest prawidłowe zachowanie.
Nigdy nie widziałeś tego błędu, ponieważ prawdopodobnie nigdy nie zrobiłbyś czegoś tak głupiego, aby spróbować przekazać 123 ref. A jeśli tak, prawdopodobnie nawet nie zauważysz, że trzeci komunikat o błędzie jest bezsensowny, ponieważ pierwszy jest poprawny i wystarczający do zdiagnozowania problemu. Ale staram się robić takie rzeczy, ponieważ próbuję złamać kompilator. Jeśli spróbujesz, zobaczysz również błędy.