Dlaczego większość „dobrze znanych” języków imperatywnych / OO umożliwia niekontrolowany dostęp do typów, które mogą reprezentować wartość „nic”?

29

Czytałem o (nie) wygodzie posiadania nullzamiast (na przykład) Maybe. Po przeczytaniu tego artykułu , jestem przekonany, że byłoby znacznie lepiej do użytkuMaybe (lub coś podobnego). Jestem jednak zaskoczony, widząc, że wszystkie „dobrze znane” imperatywne lub obiektowe języki programowania nadal używają null(co pozwala na niekontrolowany dostęp do typów, które mogą reprezentować wartość „nic”), i które Maybesą najczęściej używane w funkcjonalnych językach programowania.

Jako przykład spójrz na następujący kod C #:

void doSomething(string username)
{
    // Check that username is not null
    // Do something
}

Coś tu pachnie źle ... Dlaczego powinniśmy sprawdzać, czy argument jest zerowy? Czy nie powinniśmy zakładać, że każda zmienna zawiera odwołanie do obiektu? Jak widać, problem polega na tym, że z definicji prawie wszystkie zmienne mogą zawierać odwołanie zerowe. Co jeśli moglibyśmy zdecydować, które zmienne są „zerowalne”, a które nie? To zaoszczędziłoby nam dużo wysiłku podczas debugowania i szukania „NullReferenceException”. Wyobraź sobie, że domyślnie żaden typ nie może zawierać pustego odwołania . Zamiast tego powiedziałbyś wyraźnie, że zmienna może zawierać odwołanie zerowe , tylko jeśli naprawdę go potrzebujesz. Taki jest właśnie pomysł. Jeśli masz funkcję, która w niektórych przypadkach zawodzi (na przykład dzielenie przez zero), możesz zwrócić aMaybe<int>, stwierdzając wprost, że wynikiem może być int, ale także nic! To jeden z powodów, dla których wolę Być może zamiast wartości zerowej. Jeśli interesuje Cię więcej przykładów, sugeruję przeczytać ten artykuł .

Fakty są takie, że pomimo wad polegających na domyślnym ustawianiu większości typów na null, większość języków programowania OO faktycznie to robi. Dlatego zastanawiam się nad:

  • Jakie argumenty musiałbyś wdrożyć nullw swoim języku programowania zamiast Maybe? Czy są w ogóle jakieś powody, czy to tylko „bagaż historyczny”?

Przed udzieleniem odpowiedzi na to pytanie upewnij się, że rozumiesz różnicę między wartością null a Może.

Aochagavia
źródło
3
Sugeruję poczytać o Tonym Hoare , w szczególności o jego błędzie za miliard dolarów.
Oded
2
To był jego powód. I niefortunnym rezultatem jest to, że był to błąd skopiowany do większości późniejszych języków. Nie w językach, gdzie nulllub jego koncepcja nie istnieje (IIRC Haskell jest jednym z takich przykładów).
Oded
9
Bagaż historyczny nie jest czymś niedocenianym. I pamiętaj, że systemy operacyjne, na których się one budują, zostały napisane w językach, w których były już nullod dłuższego czasu. Nie jest łatwo po prostu to porzucić.
Oded
3
Myślę, że powinieneś rzucić nieco światła na koncepcję Może zamiast publikować link.
JeffO
1
@ Ciągi GlenH7 w C # są wartościami referencyjnymi (mogą być zerowe). Wiem, że int jest prymitywną wartością, ale przydatne było pokazanie użycia może.
aochagavia

Odpowiedzi:

15

Uważam, że jest to przede wszystkim bagaż historyczny.

Najbardziej znanym i najstarszym językiem nulljest C i C ++. Ale tutaj nullma to sens. Wskaźniki są nadal dość liczbowe i niskopoziomowe. I jak ktoś inny powiedział, w myśleniu programistów C i C ++, konieczność jawnego mówienia, że ​​wskaźnik może być null, nie ma sensu.

Na drugim miejscu jest Java. Biorąc pod uwagę, że programiści Java starali się zbliżyć do C ++, aby ułatwić sobie przejście z C ++ na Javę, prawdopodobnie nie chcieli zadzierać z taką podstawową koncepcją języka. Ponadto wdrożenie jawne nullwymagałoby znacznie więcej wysiłku, ponieważ po inicjalizacji należy sprawdzić, czy odwołanie inne niż null jest ustawione poprawnie.

Wszystkie pozostałe języki są takie same jak Java. Zwykle kopiują tak, jak robi to C ++ lub Java, a biorąc pod uwagę, jak podstawowe jest pojęcie niejawnych nulltypów referencji, naprawdę ciężko jest zaprojektować język, który używa jawnego null.

Euforyk
źródło
„Prawdopodobnie nie chcieli zadzierać z tak podstawową koncepcją języka”. Już całkowicie usunęli wskaźniki, nulla myślę, że usunięcie nie byłoby tak dużą zmianą.
svick
2
@svick W przypadku języka Java odniesienia zastępują wskaźniki. W wielu przypadkach wskaźniki w C ++ były używane w taki sam sposób, jak robią to odwołania do Java. Niektóre osoby twierdzą nawet, że Java ma wskaźniki ( programmers.stackexchange.com/questions/207196/… )
Euphoric
Oznacziłem to jako prawidłową odpowiedź. Chciałbym go zagłosować, ale nie mam wystarczającej reputacji.
aochagavia
1
Zgodzić się. Zauważ, że w C ++ (w przeciwieństwie do Java i C) wyjątek stanowi brak możliwości. std::stringnie może być null. int&nie może być null. Puszka int*i C ++ pozwala na niekontrolowany dostęp do niego z dwóch powodów: 1. ponieważ C zrobił to i 2. ponieważ powinieneś zrozumieć, co robisz, używając surowych wskaźników w C ++.
MSalters
@MSalters: Jeśli typ nie ma wartości domyślnej, którą można skopiować, wówczas utworzenie tablicy tego typu będzie wymagało wywołania konstruktora dla każdego jego elementu przed umożliwieniem dostępu do samej tablicy. Może to wymagać bezużytecznej pracy (jeśli niektóre lub wszystkie elementy zostaną nadpisane przed ich odczytaniem), może powodować komplikacje, jeśli konstruktor późniejszego elementu zawiedzie po zbudowaniu wcześniejszego elementu, i może i tak naprawdę nie osiągnąć wiele (jeśli nie można ustalić właściwej wartości dla niektórych elementów tablicy bez odczytu innych).
supercat
15

Właściwie nullto świetny pomysł. Biorąc pod uwagę wskaźnik, chcemy zaznaczyć, że ten wskaźnik nie odwołuje się do prawidłowej wartości. Więc bierzemy jedną lokalizację pamięci, stwierdzamy, że jest niepoprawna i trzymamy się tej konwencji (konwencja czasami egzekwowana za pomocą segfault). Teraz, gdy mam wskaźnik, mogę sprawdzić, czy zawiera Nothing( ptr == null) lub Some(value)( ptr != null, value = *ptr). Chcę, żebyś zrozumiał, że jest to równoważne z Maybetypem.

Problemy z tym są następujące:

  1. W wielu językach system typów nie pomaga tutaj zagwarantować odwołania o wartości innej niż null.

    Jest to bagaż historyczny, ponieważ wiele języków głównego nurtu lub języków OOP miało tylko postępowe postępy w swoich systemach typów w porównaniu z poprzednikami. Małe zmiany mają tę zaletę, że łatwiej nauczyć się nowych języków. C # to główny język, który wprowadził narzędzia na poziomie językowym, aby lepiej obsługiwać wartości zerowe.

  2. Projektanci API mogą powrócić nullpo awarii, ale nie odnoszą się do samej rzeczy po sukcesie. Często rzecz (bez odniesienia) jest zwracana bezpośrednio. To spłaszczenie o jeden poziom wskaźnika uniemożliwia użycie nullwartości.

    Jest to po prostu lenistwo po stronie projektanta i nie można na to poradzić bez narzucenia odpowiedniego zagnieżdżenia za pomocą odpowiedniego systemu typów. Niektóre osoby mogą również próbować uzasadnić to względami wydajności lub istnieniem opcjonalnych kontroli (kolekcja może zwrócić nulllub sam element, ale także podać containsmetodę).

  3. W Haskell jest ładny widok na Maybetyp jako monadę. Ułatwia to tworzenie transformacji na podstawie zawartej wartości.

    Z drugiej strony języki niskiego poziomu, takie jak C, ledwo traktują tablice jako osobny typ, więc nie jestem pewien, czego się spodziewamy. W językach OOP ze sparametryzowanym polimorfizmem Maybetyp sprawdzany w środowisku wykonawczym jest raczej trywialny do wdrożenia.

amon
źródło
„C # robi kroki od zerowych referencji.” Jakie to są kroki? Nie widziałem czegoś takiego w zmianach języka. A może masz na myśli tylko to, że wspólne biblioteki zużywają nullmniej niż kiedyś?
svick
@svick Złe sformułowanie z mojej strony. „ C # to główny język, który wprowadził narzędzia na poziomie językowym, aby lepiej obsługiwać nulls ” - mówię o Nullabletypach i ??domyślnym operatorze. Nie rozwiązuje to teraz problemu w obecności starszego kodu, ale jest krokiem w kierunku lepszej przyszłości.
amon
Zgadzam się z tobą. Głosowałbym za twoją odpowiedzią, ale nie mam wystarczającej reputacji :( Jednak Nullable działa tylko na prymitywne typy. Więc to tylko mały krok.
aochagavia
1
@svick Nullable nie ma z tym nic wspólnego. Mówimy o wszystkich typach odwołań, domyślnie zezwalając na wartość zerową, zamiast wyraźnego zdefiniowania przez programistę. Nullable można stosować tylko w przypadku typów wartości.
Euforia
@Euphoric Myślę, że twój komentarz miał być odpowiedzią na amon, nie wspomniałem Nullable.
svick
9

Rozumiem, że nullbyła to konstrukcja niezbędna do wyodrębnienia języków programowania z asemblera. 1 Programiści potrzebowali umiejętności wskazywania, że ​​wartość wskaźnika lub rejestru była not a valid valuei nullstała się powszechnym terminem dla tego znaczenia.

Wzmacniając punkt, który nulljest tylko konwencją reprezentującą koncepcję, rzeczywista wartość, nullktórą można było / może zmieniać się w zależności od języka programowania i platformy.

Jeśli projektowałeś nowy język i chciałeś go unikać, nullale maybezamiast tego używaj , zachęciłbym bardziej opisowy termin, taki jak not a valid valuelub navvwskazujący zamiar. Ale nazwa tej nie-wartości jest odrębnym pojęciem od tego, czy powinieneś pozwolić, aby nie-wartości istniały nawet w twoim języku.

Zanim zdecydujesz się na jeden z tych dwóch punktów, musisz zdefiniować, co maybeto znaczy dla twojego systemu. Może się okazać, że jest to tylko zmiana nullznaczenia not a valid valuelub może mieć inną semantyczną dla twojego języka.

Podobnie decyzja, czy sprawdzić dostęp pod kątem nulldostępu czy referencji, jest kolejną decyzją dotyczącą projektu w Twoim języku.

Aby dostarczyć trochę historii, Czakładałem, że programiści rozumieli, co próbowali zrobić, manipulując pamięcią. Ponieważ była to abstrakcja nadrzędna w stosunku do asemblera i poprzedzających go języków imperatywnych, zaryzykowałbym, że nie przyszła im do głowy myśl o bezpiecznej ochronie programisty przed niewłaściwym odniesieniem.

Uważam, że niektóre kompilatory lub ich dodatkowe narzędzia mogą zapewnić kontrolę przed nieprawidłowym dostępem do wskaźnika. Dlatego inni zauważyli ten potencjalny problem i podjęli środki w celu jego ochrony.

To, czy powinieneś na to pozwolić, zależy od tego, co chcesz osiągnąć w swoim języku i jaki poziom odpowiedzialności chcesz nałożyć na użytkowników Twojego języka. Zależy to również od umiejętności stworzenia kompilatora w celu ograniczenia tego rodzaju zachowań.

Aby odpowiedzieć na twoje pytania:

  1. „Jakie argumenty…” - Cóż, zależy to od tego, co chcesz zrobić w języku. Jeśli chcesz zasymulować dostęp bez dostępu metalu, możesz zezwolić na to.

  2. „czy to tylko bagaż historyczny?” Być może nie. nullz pewnością miał / ma znaczenie dla wielu języków i pomaga kierować wyrażaniem tych języków. Historyczny precedens mógł wpłynąć na nowsze języki i ich dopuszczenie, nullale trochę więcej jest machać rękami i zadeklarować koncepcję bezużytecznego bagażu historycznego.


1 Zobacz ten artykuł w Wikipedii, chociaż Hoare jest uznawany za wartości zerowe i języki obiektowe. Wierzę, że imperatywne języki rozwijały się wzdłuż innego drzewa genealogicznego niż Algol.


źródło
Chodzi o to, że do większości zmiennych w, powiedzmy, C # lub Java, można przypisać odwołanie zerowe. Wygląda na to, że znacznie lepiej byłoby przypisywać odniesienia zerowe tylko do obiektów, które wyraźnie wskazują, że „Może” nie ma odwołania. Moje pytanie dotyczy więc „pojęcia” null, a nie słowa.
aochagavia
2
„Referencje wskaźnika zerowego mogą pojawiać się jako błędy podczas kompilacji” Które kompilatory to potrafią?
svick
Aby być całkowicie uczciwym, nigdy nie przypisujesz zerowego odwołania do obiektu ... odwołanie do obiektu po prostu nie istnieje (odwołanie wskazuje na nic (0x000000000), co jest z definicji null).
mgw854,
Cytat specyfikacji C99 mówi o znaku zerowym , a nie o wskaźniku zerowym , to dwie bardzo różne koncepcje.
svick
2
@ GlenH7 Nie robi mi to. Kod object o = null; o.ToString();kompiluje się dla mnie dobrze, bez błędów i ostrzeżeń w VS2012. ReSharper narzeka na to, ale to nie jest kompilator.
svick
7

Jeśli spojrzysz na przykłady w cytowanym artykule, większość czasu używania Maybego nie skraca kodu. Nie eliminuje to konieczności sprawdzania Nothing. Jedyną różnicą jest to, że przypomina ci to za pomocą systemu typów.

Uwaga: mówię „przypominaj”, a nie wymuszaj. Programiści są leniwi. Jeśli programista jest przekonany, że wartość nie może być Nothing, odłóż dereferencję Maybebez jej sprawdzania, tak jak teraz wyłuskuje wskaźnik zerowy. Rezultatem końcowym jest przekonwertowanie wyjątku wskaźnika zerowego na wyjątek „może być dereferencjonowany pusty”.

Ta sama zasada ludzkiej natury ma zastosowanie w innych obszarach, w których języki programowania próbują zmusić programistów do zrobienia czegoś. Na przykład projektanci Javy próbowali zmusić ludzi do obsługi większości wyjątków, co spowodowało powstanie wielu podejrzeń, które po cichu ignorują lub ślepo propagują wyjątki.

To, co sprawia, że Maybejest miłe, to kiedy wiele decyzji jest podejmowanych poprzez dopasowanie wzorca i polimorfizm zamiast jawnych kontroli. Na przykład możesz utworzyć osobne funkcje processData(Some<T>)i z processData(Nothing<T>)którymi nie możesz sobie poradzić null. Automatycznie przenosisz obsługę błędów do osobnej funkcji, co jest bardzo pożądane w programowaniu funkcjonalnym, w którym funkcje są przekazywane i oceniane leniwie, a nie zawsze wywoływane odgórnie. W OOP preferowanym sposobem oddzielenia kodu obsługi błędów są wyjątki.

Karl Bielefeldt
źródło
Czy uważasz, że byłaby to pożądana funkcja w nowym języku OO?
aochagavia
Możesz go wdrożyć samodzielnie, jeśli chcesz uzyskać korzyści z polimorfizmu. Jedyne, czego potrzebujesz do obsługi języka, to brak możliwości zerowania. Chciałbym znaleźć sposób, aby określić to dla siebie, podobnie const, ale uczynić to opcjonalnym. Niektóre rodzaje kodu niższego poziomu, takie jak na przykład połączone listy, byłyby bardzo denerwujące w przypadku implementacji z obiektami niepozwalającymi na zerowanie.
Karl Bielefeldt,
2
Nie musisz jednak sprawdzać typu „Może”. Typ Może jest monadą, więc powinien mieć zdefiniowane funkcje map :: Maybe a -> (a -> b) i funkcje bind :: Maybe a -> (a -> Maybe b), dzięki czemu można kontynuować i wykonywać wątki dalszych obliczeń w przeważającej części przy ponownym przetwarzaniu za pomocą instrukcji if else. I getValueOrDefault :: Maybe a -> (() -> a) -> apozwala obsłużyć zerowy przypadek. Jest znacznie bardziej elegancki niż Maybe ajednoznaczne dopasowanie wzoru .
DetriusXii
1

Maybejest bardzo funkcjonalnym sposobem myślenia o problemie - istnieje rzecz, która może, ale nie musi, mieć określoną wartość. Jednak w sensie obiektowym zastępujemy tę koncepcję rzeczy (bez względu na to, czy ma ona wartość, czy nie) na obiekt. Oczywiście obiekt ma wartość. Jeśli nie, mówimy, że obiekt jest null, ale tak naprawdę rozumiemy to, że w ogóle nie ma żadnego obiektu. Odwołanie do obiektu nie wskazuje na nic. Tłumaczenie Maybena koncepcję OO nie jest niczym nowym - w rzeczywistości tworzy po prostu znacznie bardziej zaśmiecony kod. Nadal musisz mieć zerowe odwołanie do wartościMaybe<T>. Nadal musisz wykonać kontrole zerowe (w rzeczywistości musisz wykonać znacznie więcej kontroli zerowych, zaśmiecając kod), nawet jeśli są one teraz nazywane „być może czekami”. Oczywiście, napiszesz bardziej solidny kod, jak twierdzi autor, ale twierdzę, że tak jest tylko dlatego, że uczyniłeś język bardziej abstrakcyjnym i tępym, wymagającym poziomu pracy, który w większości przypadków jest niepotrzebny. Od czasu do czasu chętnie biorę wyjątek NullReferenceException, niż zajmuję się kodem spaghetti, który sprawdza, może za każdym razem, gdy uzyskuję dostęp do nowej zmiennej.

mgw854
źródło
2
Myślę, że doprowadziłoby to do mniej zerowych kontroli, ponieważ musisz tylko sprawdzić, czy widzisz Może <T> i nie musisz się martwić o resztę typów.
aochagavia
1
@svick Maybe<T>musi zezwolić nulljako wartość, ponieważ wartość może nie istnieć. Jeśli tak Maybe<MyClass>, i nie ma wartości, pole wartości musi zawierać odwołanie zerowe. Nie ma nic, co mogłoby być w pełni bezpieczne.
mgw854,
1
@ mgw854 Pewnie, że jest. W języku OO Maybemoże to być klasa abstrakcyjna, z dwiema dziedziczącymi po niej klasami: Some(która ma pole dla wartości) i None(która nie ma tego pola). W ten sposób wartość nigdy nie jest null.
svick
6
Domyślnie „nie-zerowalność” i być może <T> możesz być pewien, że niektóre zmienne zawsze zawierają obiekty. Mianowicie wszystkie zmienne, które nie są Może <T>
aochagavia
3
@ mgw854 Celem tej zmiany byłoby zwiększenie siły ekspresji dla programistów. W tej chwili programista musi zawsze zakładać, że referencja lub wskaźnik może mieć wartość NULL i musi sprawdzić, czy jest użyteczna wartość. Wdrażając tę ​​zmianę, dajesz programistom moc, aby powiedzieć, że naprawdę potrzebuje poprawnej wartości i masz sprawdzanie kompilatora, aby upewnić się, że poprawna wartość została przekazana. Ale wciąż daje opcję programistyczną, aby wyrazić zgodę i nie przekazywać żadnej wartości.
Euforia
1

Pojęcie nullmożna łatwo prześledzić z powrotem do C, ale nie na tym polega problem.

Moim codziennym językiem jest C # i zachowałbym nulljedną różnicę. C # ma dwa rodzaje typów, wartości i referencje . Wartości nigdy nie mogą być null, ale czasami chciałbym wyrazić, że żadna wartość nie jest w porządku. Aby to zrobić, C # używa Nullabletypów, więc intbyłaby to wartość i int?wartość zerowa. Tak myślę, że typy referencyjne powinny również działać.

Zobacz także: Odwołanie zerowe nie może być pomyłką :

Odwołania zerowe są pomocne, a czasem niezbędne (rozważ, ile kłopotów możesz, jeśli możesz zwrócić ciąg w C ++). Błąd naprawdę nie polega na istnieniu wskaźników zerowych, ale na sposobie, w jaki obsługuje je system typów. Niestety większość języków (C ++, Java, C #) nie obsługuje ich poprawnie.

Daniel Little
źródło
0

Myślę, że dzieje się tak, ponieważ programowanie funkcjonalne jest bardzo zaniepokojone typami , szczególnie tymi, które łączą inne typy (krotki, funkcje jako typy pierwszej klasy, monady itp.) Niż programowanie obiektowe (lub przynajmniej początkowo tak zrobiło).

Nowoczesne wersje języków programowania, o których myślę, że mówisz (C ++, C #, Java), oparte są na językach, które nie miały żadnej formy programowania ogólnego (C, C # 1.0, Java 1). Bez tego nadal można upiec w języku pewną różnicę między obiektami zerowalnymi i nierozpoznawalnymi (takimi jak odwołania do C ++, które nie mogą być null, ale są również ograniczone), ale jest to o wiele mniej naturalne.

svick
źródło
Myślę, że w przypadku programowania funkcjonalnego jest tak, że FP nie ma typów odniesienia ani wskaźników. W FP wszystko jest wartością. A jeśli masz typ wskaźnika, łatwo jest powiedzieć „wskaźnik do niczego”.
Euforia
0

Myślę, że podstawowym powodem jest to, że stosunkowo niewiele kontroli zerowych jest wymaganych, aby program był „bezpieczny” przed uszkodzeniem danych. Jeśli program próbuje użyć zawartości elementu tablicy lub innej lokalizacji pamięci, która powinna zostać zapisana z prawidłowym odwołaniem, ale nie została wykonana, najlepszym rozwiązaniem jest zgłoszenie wyjątku. Idealnie, wyjątek wskaże dokładnie, gdzie wystąpił problem, ale ważne jest, że jakiś wyjątek zostanie zgłoszony, zanim odwołanie zerowe zostanie zapisane gdzieś, co może spowodować uszkodzenie danych. O ile metoda nie przechowuje obiektu bez wcześniejszego użycia go w jakiś sposób, próba użycia obiektu będzie sama w sobie stanowić swego rodzaju „kontrolę zerową”.

Jeśli ktoś chce się upewnić, że odwołanie zerowe, które pojawia się tam, gdzie nie powinno, spowoduje określony wyjątek inny niż NullReferenceException, często konieczne będzie włączenie kontroli zerowej w całym miejscu. Z drugiej strony samo upewnienie się, że wystąpi jakiś wyjątek, zanim odwołanie zerowe może spowodować „uszkodzenie” wykraczające poza to, co już zostało zrobione, często wymaga stosunkowo niewielu testów - testowanie byłoby zwykle wymagane tylko w przypadkach, w których obiekt przechowywałby odniesienia, nie próbując go używać, i albo odniesienie zerowy byłoby zastąpić ważny jeden, lub spowodowałoby to inny kod błędnie interpretować inne aspekty stanu programu. Takie sytuacje istnieją, ale nie są tak powszechne; większość przypadkowych zerowych odniesień zostanie bardzo szybko złapanaczy ktoś je sprawdza, czy nie .

supercat
źródło
ten post jest raczej trudny do odczytania (ściana tekstu). Czy mógłbyś edytować go w lepszym kształcie?
komara
1
@gnat: Czy to lepiej?
supercat
0

Maybe,” jak napisano, jest konstrukcją wyższego poziomu niż zero. Używając więcej słów, aby to zdefiniować, być może „wskaźnik do rzeczy lub wskaźnik do niczego, ale kompilator nie otrzymał jeszcze wystarczających informacji, aby ustalić, który”. To zmusza cię do ciągłego sprawdzania każdej wartości, chyba że zbudujesz specyfikację kompilatora, która jest wystarczająco inteligentna, aby nadążyć za pisanym kodem.

Możesz wykonać implementację Może w języku, który ma wartości zerowe. C ++ ma jeden w postaci boost::optional<T>. Wyrównanie wartości null z Może jest bardzo trudne. W szczególności, jeśli mam Maybe<Just<T>>, nie mogę przypisać go do wartości null (ponieważ taka koncepcja nie istnieje), podczas gdy T**w języku o wartości null bardzo łatwo jest przypisać wartość null. To zmusza do użycia Maybe<Maybe<T>>, co jest całkowicie poprawne, ale zmusi cię do wykonania o wiele więcej kontroli, aby użyć tego obiektu.

Niektóre języki funkcjonalne używają Może dlatego, że wartość null wymaga niezdefiniowanego zachowania lub obsługi wyjątków, z których żaden nie jest łatwym pojęciem do mapowania na składnie języka funkcjonalnego. Być może rolę tę pełni lepiej w takich sytuacjach funkcjonalnych, ale w językach proceduralnych null jest królem. Nie jest to kwestia dobra i zła, tylko kwestia tego, co ułatwia powiedzenie komputerowi, aby zrobił to, co chcesz.

Cort Ammon - Przywróć Monikę
źródło