Dodając do tego, co ludzie mówili o Maybe
konstruktorze typów:
Kolejnym dużym zyskiem, poza tym, że nie ryzykuje się NPE, jest semantyczny. W świecie funkcjonalnym, w którym mamy do czynienia z funkcjami czystymi, lubimy tworzyć funkcje, które po zastosowaniu są dokładnie równoważne ich wartości zwracanej . Rozważ przypadek String.reverse()
: Jest to funkcja, której dany ciąg reprezentuje odwróconą wersję tego ciągu. Wiemy, że ten ciąg istnieje, ponieważ każdy ciąg można odwrócić (ciągi są w zasadzie uporządkowanymi zestawami znaków).
A teraz co findCustomer(int id)
? Ta funkcja reprezentuje klienta, który ma podany identyfikator. Jest to coś, co może istnieć lub nie. Pamiętaj jednak, że funkcje mają jedną zwracaną wartość, więc nie można tak naprawdę powiedzieć „ta funkcja zwraca klienta o podanym identyfikatorze LUB zwraca null
.
To jest mój główny problem zarówno ze zwracaniem, jak null
i zwracaniem pustego obiektu. Wprowadzają w błąd. null
nie jest klientem i nie jest tak naprawdę „nieobecnością klienta”. To brak NIC. Jest to po prostu typ bez wskaźnika do NIC. Bardzo niski poziom, bardzo brzydka i podatna na błędy. Wydaje mi się, że tutaj również jest pusty obiekt. Klient zerowy JEST klientem. To nie jest brak jednego, to nie klient z prośbą o identyfikator, więc zwrot jest po prostu NIEPRAWIDŁOWY. To NIE jest klient, o którego prosić, ale nadal twierdzisz, że zwróciłeś klienta. Ma zły identyfikator, najwyraźniej jest to błąd. Łamie kontrakt sugerowany przez nazwę i podpis metody. Wymaga to, aby kod klienta zakładał pewne rzeczy o twoim projekcie lub czytał dokumentację.
Oba te problemy rozwiązuje Maybe Customer
. Nagle nie mówimy „ta funkcja reprezentuje klienta o podanym identyfikatorze”. Mówimy „ta funkcja reprezentuje klienta o podanym identyfikatorze, jeśli istnieje . Jest teraz bardzo jasny i wyraźny na temat tego, co robi. Jeśli poprosisz o klienta z nieistniejącym identyfikatorem, otrzymasz Nothing
. Jak to jest lepsze? niż null
? Nie tylko z powodu ryzyka NPE, ale także dlatego, że rodzaj Nothing
nie jest po prostu Maybe
. Jest Maybe Customer
. Ma znaczenie semantyczne. W szczególności oznacza „brak klienta”, co oznacza, że taki klient nie istnieje.
Innym problemem z zerowym jest oczywiście to, że jest niejednoznaczny. Czy to dlatego, że nie znalazłeś klienta, czy wystąpił błąd połączenia z bazą danych, czy po prostu nie mogę go zobaczyć?
Jeśli masz kilka takich błędów do obsłużenia, możesz albo zgłosić wyjątki dla tych wersji, albo (i ja wolę w ten sposób) możesz zwrócić an Either CustomerLoadError Customer
, reprezentujący coś, co poszło nie tak, lub zwrócony klient. Ma wszystkie zalety Maybe Customer
, pozwalając jednocześnie określić, co może pójść nie tak.
Najważniejsze, czego szukam, to uchwycenie kontraktu funkcji w jej podpisie. Nie zakładaj rzeczy, nie polegaj na ulotnych konwencjach, bądź wyraźny.