Dlaczego odwołania zerowe są odrzucane, a zgłaszanie wyjątków jest uważane za prawidłowe?

21

Nie do końca rozumiem konsekwentne niszczenie referencji zerowych przez niektórych ludzi w języku programowania. Co jest w nich takiego złego? Jeśli poproszę o dostęp do odczytu pliku, który nie istnieje, cieszę się, że otrzymam wyjątek lub odwołanie zerowe, a jednak wyjątki są uważane za dobre, ale odniesienia zerowe są uważane za złe. Jakie jest tego uzasadnienie?

davidk01
źródło
2
Niektóre języki powodują awarię zerową lepiej niż inne. Dla „kodu zarządzanego”, takiego jak .Net / Java, zerowe odwołanie jest po prostu innym rodzajem problemu, podczas gdy inny natywny kod może nie traktować tego tak płynnie (nie wspomniałeś o konkretnym języku). Nawet w zarządzanym świecie czasami chcesz napisać kod zabezpieczający przed awarią (osadzony ?, broń?), A czasem głośno suka jak najszybciej (testy jednostkowe). Oba typy kodu mogą wywoływać się w tej samej bibliotece - to byłby problem. Ogólnie rzecz biorąc, uważam, że kod, który nie szkodzi uczuciom komputera, jest złym pomysłem. W każdym razie bezpieczeństwo awaryjne jest trudne.
Job
@Job: To lenistwo. Jeśli wiesz, jak obsłużyć wyjątek, obsłużysz go. Czasami ta obsługa może obejmować zgłoszenie kolejnego wyjątku, ale nigdy nie należy dopuszczać, aby wyjątek odwołania zerowego nie był obsługiwany. Zawsze. To koszmar każdego programisty konserwacji; to najbardziej bezużyteczny wyjątek w całym drzewie. Po prostu zapytaj Przepełnienie stosu .
Aaronaught
lub inaczej: dlaczego nie zwrócić jakiegoś kodu reprezentującego informację o błędzie. Ten argument będzie szalał przez wiele lat.
gbjbaanb

Odpowiedzi:

24

Odwołania zerowe nie są „unikane” bardziej niż wyjątki, przynajmniej przez kogokolwiek, kogo znałem lub czytałem. Myślę, że nie rozumiesz konwencjonalnej mądrości.

Zła jest próba uzyskania dostępu do pustego odwołania (lub wyrejestrowanie pustego wskaźnika itp.). Jest to złe, ponieważ zawsze oznacza błąd; nigdy nie zrobiłby czegoś takiego celowo, a jeśli robi to celowo, to jeszcze gorzej, bo to co niemożliwe do odróżnienia od oczekiwanego zachowanie buggy zachowań.

Istnieją pewne grupy skrajne, które z jakiegoś powodu tak naprawdę nienawidzą pojęcia nieważności, ale jak zauważa Ed , jeśli nie masz, nullalbo nilbędziesz musiał po prostu zastąpić to czymś innym, co może prowadzić do czegoś gorsze niż awaria (np. uszkodzenie danych).

W rzeczywistości wiele ram obejmuje obie koncepcje; na przykład w .NET częstym wzorcem, który zobaczysz, jest para metod, z których jedna poprzedza słowo Try(np. TryGetValue). W takim Tryprzypadku odwołanie jest ustawione na wartość domyślną (zwykle null), aw innym przypadku zgłaszany jest wyjątek. W obu podejściach nie ma nic złego; oba są często używane w środowiskach, które je obsługują.

To naprawdę wszystko zależy od semantyki. Jeśli nulljest poprawną wartością zwracaną, tak jak w ogólnym przypadku przeszukiwania kolekcji, to zwróć null. Z drugiej strony, jeśli to nie jest prawidłową wartością powrót - na przykład, patrząc rekordu przy użyciu klucza podstawowego dostarczonej z własnej bazy danych - to powrót nullbyłby zły pomysł, ponieważ rozmówca nie będzie spodziewał i zapewne nie będzie tego sprawdzać.

Naprawdę bardzo łatwo jest ustalić, którego semantycznego użyć: Czy ma sens nieokreślony wynik działania funkcji? Jeśli tak, możesz zwrócić odwołanie zerowe. Jeśli nie, wyrzuć wyjątek.

Aaronaught
źródło
5
W rzeczywistości istnieją języki, które nie mają wartości zerowej lub zerowej i nie muszą „zamieniać go na coś innego”. Odwoływalne odniesienia sugerują, że coś może tam być lub nie. Jeśli po prostu wymagasz od użytkownika jawnego sprawdzenia, czy coś tam jest, problem został rozwiązany. Zobacz haskell dla prawdziwego przykładu.
Johanna Larsson
3
@ErikKronberg, tak, „błąd w miliardach dolarów” i cały ten nonsens, parada ludzi kłusujących to i twierdzących, że jest świeży i fascynujący, nigdy się nie kończy, dlatego poprzedni wątek komentarza został usunięty. Te rewolucyjne zamienniki, których ludzie nigdy nie zaniedbują, są zawsze jakimś wariantem zerowego obiektu, opcji lub kontraktu, które w rzeczywistości nie eliminują magicznie podstawowego błędu logicznego, po prostu odpowiednio go odraczają lub promują. W każdym razie, jest to oczywiście pytanie o języki programowania, które dzieje mieć null, tak naprawdę, Haskell jest całkiem nieistotne tutaj.
Aaronaught
1
poważnie argumentujesz, że nie wymaganie testu zerowego jest tak samo dobre, jak wymaganie go?
Johanna Larsson
3
@ErikKronberg: Tak, „poważnie argumentuję”, że testowanie pod kątem wartości zerowej nie różni się szczególnie od (a) konieczności zaprojektowania każdej warstwy aplikacji wokół zachowania obiektu zerowego, (b) konieczności dopasowania wzorca Opcje przez cały czas lub (c) niedozwolenie odbiorcy powiedzenia „nie wiem” i wymuszenie wyjątku lub awarii. Jest to powód, dlaczego nullprzetrwała tak dobrze przez tak długi czas, a większość ludzi, którzy mówią inaczej wydają się być akademicy z małymi projektowania doświadczenie aplikacjach rzeczywistych z ograniczeniami jak niekompletnych wymogów lub ewentualnego konsystencji.
Aaronaught
3
@Aaronaught: Czasami żałuję, że nie było przycisku z komentarzem. Nie ma powodu, aby tak twierdzić.
Michael Shaw
11

Duża różnica polega na tym, że jeśli pominiesz kod do obsługi wartości NULL, twój kod będzie nadal prawdopodobnie zawieszał się na późniejszym etapie z jakimś niepowiązanym komunikatem o błędzie, przy czym tak jak w przypadku wyjątków, wyjątek byłby zgłaszany w początkowym punkcie awarii (otwarcie plik do odczytu w twoim przykładzie).

John Gaines Jr.
źródło
4
Brak obsługi wartości NULL byłby rozmyślną ignorancją interfejsu między kodem a tym, co go zwróciło. Programiści, którzy popełniliby ten błąd, robili innych w języku, który nie robi wartości NULL.
Blrfl
@Blrfl, najlepiej, że metody są dość krótkie, dlatego łatwo jest dowiedzieć się, gdzie dokładnie występuje problem. Dobry debugger może zwykle dobrze wyśledzić wyjątek odniesienia zerowego, nawet jeśli kod jest długi. Co mam zrobić, jeśli próbuję odczytać krytyczne ustawienie z rejestru, którego nie ma? Mój rejestr jest zawalony i lepiej jest, gdy zawiodę i zirytuję użytkownika, niż dyskretne odtworzenie węzła i ustawienie go jako domyślnego. Co jeśli wirus to zrobił? Więc jeśli otrzymam wartość zerową, czy powinienem rzucić specjalny wyjątek, czy po prostu pozwolić mu zgrać? Jaka jest duża różnica krótkimi metodami?
Job
@Job: Co jeśli nie masz debugera? Czy zdajesz sobie sprawę, że 99,99% czasu, w którym aplikacja będzie działać w środowisku wydania? Kiedy tak się stanie, będziesz żałować, że nie użyłeś bardziej znaczącego wyjątku. Być może Twoja aplikacja nadal będzie musiała zawieść i zirytować użytkownika, ale przynajmniej wyświetli informacje debugowania, które pozwolą ci szybko wyśledzić problem, ograniczając w ten sposób irytację do minimum.
Aaronaught
@ Birfl, czasami nie chcę zajmować się przypadkiem, w którym zerowanie byłoby naturalne, aby zwrócić. Załóżmy na przykład, że mam klucze mapowania kontenera na wartości. Jeśli moja logika gwarantuje, że nigdy nie podejmę próby odczytania wartości, których wcześniej nie zapisałem, to nigdy nie powinienem otrzymać wartości null. W takim przypadku wolałbym raczej wyjątek, który zapewnia tyle informacji, ile to możliwe, aby wskazać, co poszło źle, zamiast zwracania wartości null w tajemniczy sposób, by zawiódł gdzie indziej w programie.
Winston Ewert
Innymi słowy, z wyjątkami, muszę jawnie poradzić sobie z nietypowym przypadkiem, bo inaczej mój program natychmiast umiera. W przypadku odwołań o wartości NULL, jeśli kod nie obsługuje jawnie nietypowego przypadku, spróbuje utykać. Myślę, że lepiej jest przyjąć przypadek niepowodzenia teraz.
Winston Ewert
8

Ponieważ wartości null nie są niezbędną częścią języka programowania i stanowią spójne źródło błędów. Jak mówisz, otwarcie pliku może spowodować błąd, który może zostać przesłany z powrotem jako zerowa wartość zwracana lub za pośrednictwem wyjątku. Jeśli wartości zerowe nie są dozwolone, istnieje spójny, pojedynczy sposób komunikowania niepowodzenia.

Ponadto nie jest to najczęstszy problem z zerami. Większość ludzi pamięta, aby sprawdzić, czy nie ma wartości null po wywołaniu funkcji, która może ją zwrócić. Problem pojawia się znacznie częściej w twoim własnym projekcie, pozwalając, aby zmienne były zerowe w różnych punktach wykonania programu. Możesz zaprojektować swój kod w taki sposób, aby wartości null nigdy nie były dozwolone, ale jeśli null nie byłby dozwolony na poziomie języka, żadne z nich nie byłoby konieczne.

Jednak w praktyce nadal potrzebujesz jakiegoś sposobu na wskazanie, czy zmienna jest inicjowana czy nie. Miałbyś wtedy formę błędu, w którym twój program nie ulega awarii, ale zamiast tego kontynuuje używanie pewnej nieprawidłowej wartości domyślnej. Naprawdę nie wiem, co jest lepsze. Za moje pieniądze lubię rozbijać wcześnie i często.

Ed S.
źródło
Rozważ niezainicjowaną podklasę z ciągiem identyfikującym, a wszystkie jej metody zgłaszają wyjątki. Jeśli jeden z nich się kiedykolwiek pojawi, wiesz, co się stało. W systemach wbudowanych z ograniczoną pamięcią wersja produkcyjna fabryki niezainicjowanej może po prostu zwrócić wartość null.
Jim Balter
3
@Jim Balter: Podejrzewam, że jestem zdezorientowany, jak to naprawdę pomogłoby w praktyce. W każdym nietrywialnym programie będziesz musiał w pewnym momencie poradzić sobie z wartościami, których nie można zainicjować. Musi więc istnieć jakiś sposób na oznaczenie wartości domyślnej. Dlatego nadal musisz to sprawdzić przed kontynuowaniem. Zamiast potencjalnej awarii, potencjalnie pracujesz teraz z nieprawidłowymi danymi.
Ed S.
1
Wiesz także, co się stało, gdy otrzymasz nullwartość zwrotną: Żądane informacje nie istnieją. Nie ma różnicy. Tak czy inaczej, osoba dzwoniąca musi sprawdzić wartość zwracaną, jeśli faktycznie musi użyć tych informacji do określonego celu. Czy jest to sprawdzanie poprawności nullobiektu zerowego, czy monady, nie ma praktycznej różnicy.
Aaronaught
1
@Jim Balter: Racja, nadal nie widzę praktycznej różnicy i nie widzę, jak to ułatwia życie ludziom piszącym prawdziwe programy poza środowiskiem akademickim. Nie oznacza to, że nie ma korzyści, po prostu nie wydają mi się oczywiste.
Ed S.
1
Wyjaśniłem praktyczną różnicę w przypadku niezainicjowanej klasy dwukrotnie - identyfikuje pochodzenie pustego elementu - umożliwiając wskazanie błędu, gdy wystąpi dereferencja pustego. Jeśli chodzi o języki zaprojektowane wokół paradygmatów zerowych, unikają problemu od samego początku - zapewniają alternatywne sposoby programowania. Unikają niezainicjowanych zmiennych; to może wydawać się trudne do zrozumienia, jeśli nie znasz ich. Programowanie strukturalne, które pozwala również uniknąć dużej liczby błędów, było kiedyś uważane za „akademickie”.
Jim Balter
5

Tony Hoare, który stworzył pomysł zerowego odniesienia, nazywa to błędem w wysokości miliona dolarów .

Problem nie dotyczy samych odwołań zerowych, ale braku odpowiedniego sprawdzania typu w większości (w przeciwnym razie) bezpiecznych językach.

Ten brak wsparcia z języka oznacza, że ​​błędy „null-bug” mogą czaić się w programie przez długi czas, zanim zostaną wykryte. Taka jest natura błędów, ale wiadomo, że „błędów zerowych” można teraz uniknąć.

Ten problem występuje szczególnie w C lub C ++ (na przykład) z powodu „twardego” błędu, który powoduje (natychmiastowe zawieszenie programu, bez eleganckiego przywracania).

W innych językach zawsze pojawia się pytanie, jak sobie z nimi poradzić.

W Javie lub C # dostaniesz wyjątek, jeśli spróbujesz wywołać metodę na odwołaniu zerowym, i może być w porządku. Dlatego większość programistów Java lub C # jest do tego przyzwyczajona i nie rozumie, dlaczego ktoś chciałby robić inaczej (i śmiać się z C ++).

W Haskell musisz jawnie podać akcję dla przypadku zerowego, dlatego programiści Haskell wychwalają swoich kolegów, ponieważ dobrze to zrobili (prawda?).

To tak naprawdę stara debata na temat kodu błędu / wyjątku, ale tym razem z wartością Sentinel zamiast kodu błędu.

Jak zawsze to, co jest najbardziej odpowiednie, naprawdę zależy od sytuacji i semantyki, której szukasz.

Matthieu M.
źródło
Dokładnie. nullnaprawdę jest zły, ponieważ psuje system typów . (To prawda, że ​​alternatywa ma wadę, przynajmniej w niektórych językach).
Ślimak mechaniczny
2

Do wskaźnika zerowego nie można dołączyć czytelnego dla człowieka komunikatu o błędzie.

(Możesz jednak zostawić komunikat błędu w pliku dziennika.)

W niektórych języków / środowiskach, które pozwalają arytmetyki wskaźników, jeśli jeden z argumentów jest null pointer i dopuszcza do obliczeń, wynik byłby nieważny , niż null pointer. (*) Więcej mocy dla ciebie.

(*) Zdarza się to często w programowaniu COM , w którym próba wywołania metody interfejsu, ale wskaźnik interfejsu jest zerowy, spowoduje wywołanie nieprawidłowego adresu, który jest prawie, ale nie do końca, dokładnie różny od zera.

rwong
źródło
2

Zwracanie wartości NULL (lub zera numerycznego lub logicznego fałszu) w celu zasygnalizowania błędu jest błędne zarówno pod względem technicznym, jak i koncepcyjnym.

Z technicznego punktu widzenia obciążasz programistę sprawdzaniem wartości zwracanej od razu , dokładnie w punkcie, w którym jest ona zwracana. Jeśli otworzysz dwadzieścia plików z rzędu, a sygnalizacja błędu zostanie wykonana przez zwrócenie wartości NULL, wówczas konsumujący kod musi sprawdzić każdy plik odczytywany indywidualnie i zerwać wszelkie pętle i podobne konstrukcje. To idealny przepis na zaśmiecony kod. Jeśli jednak zdecydujesz się zasygnalizować błąd poprzez zgłoszenie wyjątku, konsumujący kod może zdecydować się natychmiast obsłużyć wyjątek lub pozwolić, aby pojawił się tyle poziomów, ile potrzeba, nawet w wywołaniach funkcji. To sprawia, że ​​kod jest znacznie czystszy.

Koncepcyjnie, jeśli otworzysz plik i coś pójdzie nie tak, zwracanie wartości (nawet NULL) jest nieprawidłowe. Nie masz nic do zwrócenia, ponieważ operacja się nie zakończyła. Zwracanie NULL jest koncepcyjnym odpowiednikiem „Udało mi się odczytać plik, a oto, co zawiera - nic”. Jeśli to właśnie chcesz wyrazić (to znaczy, jeśli NULL ma sens jako rzeczywisty wynik dla danej operacji), to w każdym razie zwróć NULL, ale jeśli chcesz zasygnalizować błąd, użyj wyjątków.

Historycznie błędy były zgłaszane w ten sposób, ponieważ języki programowania, takie jak C, nie mają wbudowanej obsługi wyjątków, a zalecany sposób (przy użyciu skoków w dal) jest nieco owłosiony i nieco sprzeczny z intuicją.

Problem ma także stronę konserwacyjną: z wyjątkami musisz napisać dodatkowy kod, aby poradzić sobie z awarią; jeśli tego nie zrobisz, program zawiedzie wcześnie i mocno (co jest dobre). Jeśli zwrócisz NULL, aby zasygnalizować błędy, domyślnym zachowaniem programu jest zignorowanie błędu i kontynuowanie, dopóki nie doprowadzi to do innych problemów na drodze - uszkodzonych danych, segfault, NullReferenceExceptions, w zależności od języka. Aby wcześnie i głośno zasygnalizować błąd, musisz napisać dodatkowy kod i zgadnij, co: to część, która zostaje pominięta, gdy masz napięty termin.

tdammers
źródło
1

Jak już wspomniano, wiele języków nie przekształca dereferencji wskaźnika zerowego w możliwy do wychwycenia wyjątek. Jest to stosunkowo nowoczesna sztuczka. Kiedy po raz pierwszy wykryto problem ze wskaźnikiem zerowym, wyjątki jeszcze nie zostały wynalezione.

Jeśli dopuścisz wskaźniki zerowe jako prawidłowy przypadek, będzie to przypadek specjalny. Potrzebujesz logiki obsługi specjalnych przypadków, często w wielu różnych miejscach. To dodatkowa złożoność.

Bez względu na to, czy dotyczy potencjalnie zerowych wskaźników, czy nie, jeśli nie używasz wyjątków do obsługi wyjątkowych przypadków, musisz obsłużyć te wyjątkowe przypadki w inny sposób. Zazwyczaj każde wywołanie funkcji musi być sprawdzane pod kątem wyjątkowych przypadków, aby zapobiec niewłaściwemu wywołaniu funkcji lub wykryć przypadek awarii, gdy funkcja kończy działanie. To dodatkowa złożoność, której można uniknąć za pomocą wyjątków.

Większa złożoność zwykle oznacza więcej błędów.

Alternatywami do używania zerowych wskaźników w strukturach danych (np. Do oznaczenia początku / końca połączonej listy) są użycie elementów wartowniczych. Mogą zapewnić tę samą funkcjonalność przy znacznie mniejszej złożoności. Istnieją jednak inne sposoby zarządzania złożonością. Jednym ze sposobów jest zawinięcie potencjalnie pustego wskaźnika w inteligentną klasę wskaźnika, aby kontrole zerowe były potrzebne tylko w jednym miejscu.

Co zrobić ze wskaźnikiem zerowym, gdy zostanie wykryty? Jeśli nie możesz wbudować obsługi wyjątkowych przypadków, zawsze możesz zgłosić wyjątek i skutecznie przekazać to połączenie specjalnemu dzwoniącemu. I to właśnie dokładnie robią niektóre języki, gdy wyrejestrujesz wskaźnik zerowy.

Steve314
źródło
1

Specyficzne dla C ++, ale istnieją tam odwołania zerowe, ponieważ semantyka zerowa w C ++ jest powiązana z typami wskaźników. Rozsądne jest, aby funkcja otwierania pliku zawiodła i zwróciła wskaźnik zerowy; w rzeczywistości fopen()funkcja robi dokładnie to.

MSalters
źródło
Rzeczywiście, jeśli znajdziesz się w C ++ z zerowym odwołaniem, dzieje się tak, ponieważ twój program jest już zepsuty .
Kaz Dragon
1

To zależy od języka.

Na przykład Objective-C pozwala bez problemu wysłać wiadomość do obiektu zerowego (zerowego). Wezwanie do zera również zwraca zero i jest uważane za funkcję języka.

Osobiście mi się podoba, ponieważ możesz polegać na tym zachowaniu i unikać tych zawiłych zagnieżdżonych if(obj == null)konstrukcji.

Na przykład:

if (myObject != nil && [myObject doSomething])
{
    ...
}

Można skrócić do:

if ([myObject doSomething])
{
    ...
}

Krótko mówiąc, sprawia, że ​​kod jest bardziej czytelny.

Martin Wickman
źródło
0

Nie daję się zwieść, czy zwrócisz wartość zerową, czy zgłosisz wyjątek, o ile go dokumentujesz.

SnoopDougieDoug
źródło
A także nazwij to: GetAddressMaybelub GetSpouseNameOrNull.
rwong
-1

Odwołanie zerowe zwykle występuje, ponieważ coś w logice programu zostało pominięte, tj .: dotarłeś do linii kodu bez przechodzenia przez wymagane ustawienia dla tego bloku kodu.

Z drugiej strony, jeśli zgłosisz wyjątek dla czegoś, oznacza to, że rozpoznałeś, że konkretna sytuacja może wystąpić podczas normalnej pracy programu i że jest on obsługiwany.

Dave
źródło
2
Odwołanie zerowe może „wystąpić” z wielu powodów, z których bardzo niewiele dotyczy pominięcia czegoś. Być może mylisz się z wyjątkiem zerowej referencji .
Aaronaught
-1

Odwołania zerowe są często bardzo przydatne: Na przykład element na połączonej liście może mieć następcę lub nie mieć go. Używanie null„bez następcy” jest całkowicie naturalne. Lub, osoba może mieć małżonka lub nie - używanie nulldla „osoba nie ma małżonka” jest całkowicie naturalne, o wiele bardziej naturalne niż posiadanie pewnej „nie ma małżonka” - szczególna wartość, do której Person.Spouseczłonek mógłby się odwoływać.

Ale: Wiele wartości nie jest opcjonalnych. W typowym programie OOP powiedziałbym, że ponad połowa referencji nie może być nullpo inicjalizacji, inaczej program się nie powiedzie. W przeciwnym razie kod musiałby być wypełniony if (x != null)czekami. Dlaczego więc każde odwołanie powinno być domyślnie zerowane? Naprawdę powinno być na odwrót: zmienne powinny domyślnie nie mieć wartości zerowej, a Ty powinieneś wyraźnie powiedzieć „och, i ta wartość też może być null”.

nikie
źródło
czy jest coś z tej dyskusji, którą chciałbyś dodać do swojej odpowiedzi? Ten wątek komentarza trochę się rozgrzał i chcielibyśmy to posprzątać. Każdą dłuższą dyskusję należy prowadzić na czacie .
Pośród wszystkich tych sprzeczek mógł istnieć jeden lub dwa punkty faktycznego zainteresowania. Niestety, nie widziałem komentarza Marka, dopóki nie usunąłem obszernej dyskusji. W przyszłości prosimy o zaznaczenie swojej odpowiedzi moderatorom, jeśli chcesz zachować komentarze, dopóki nie będziesz mieć czasu na ich przejrzenie i odpowiednią edycję.
Josh K
-1

Twoje pytanie jest myląco sformułowane. Czy masz na myśli wyjątek zerowy (który jest faktycznie spowodowany próbą dereferencja null)? Wyraźnym powodem, dla którego nie chcemy tego rodzaju wyjątku, jest to, że nie daje on żadnych informacji na temat tego, co poszło źle, a nawet kiedy - wartość można ustawić na wartość null w dowolnym momencie programu. Piszesz: „Jeśli poproszę o dostęp do odczytu pliku, który nie istnieje, to cieszę się, że otrzymałem wyjątek lub odwołanie zerowe” - ale nie powinieneś być szczęśliwy, gdy dostaniesz coś, co nie wskazuje przyczyny . Nigdzie w ciągu „nie podjęto próby wyrejestrowania wartości null” nie ma wzmianki o czytaniu ani o nieistnieniu plików. Być może masz na myśli, że byłbyś szczęśliwy, gdybyś był zerowy jako wartość zwracana z wywołania odczytu - to zupełnie inna sprawa, ale wciąż nie daje ci żadnych informacji o tym, dlaczego odczyt się nie powiódł; to'

Jim Balter
źródło
Nie, nie mam na myśli wyjątku zerowego odniesienia. We wszystkich językach, które znam, niezainicjowane, ale zadeklarowane zmienne mają formę zerową.
davidk01
Ale twoje pytanie nie dotyczyło niezainicjowanych zmiennych. Są też języki, które nie używają null dla niezainicjowanych zmiennych, ale zamiast tego używają opakowań, które opcjonalnie mogą zawierać wartość - na przykład Scala i Haskell.
Jim Balter
1
„... ale zamiast tego używaj opakowań, które opcjonalnie mogą zawierać wartość .” Co oczywiście nie jest niczym typu zerowalnego .
Aaronaught
1
W haskell nie ma czegoś takiego jak niezainicjowana zmienna. Możesz potencjalnie zadeklarować IORef i zaszczepić go wartością None jako wartość początkową, ale jest to prawie analogia do deklarowania zmiennej w innym języku i pozostawienia jej niezainicjowanej, co niesie ze sobą te same problemy. Pracując w czysto funkcjonalnym rdzeniu poza IO programiści haskell nie mają możliwości odwoływania się do typów referencji, więc nie ma problemu z zerową referencją.
davidk01
1
Jeśli masz wyjątkową wartość „brakującą”, jest to dokładnie to samo, co wyjątkowa wartość „zerowa” - jeśli masz dostępne te same narzędzia do jej obsługi. To znaczące „jeśli”. Potrzebujesz dodatkowej złożoności, aby w obu przypadkach poradzić sobie z tą sprawą. W Haskell dopasowanie wzorca i system typów zapewnia sposób na zarządzanie tą złożonością. Istnieją jednak inne narzędzia do zarządzania złożonością w innych językach. Wyjątki są jednym z takich narzędzi.
Steve314