Jaka jest różnica między opcjami opcjonalnymi a typem zerowym

15

Swift ma Optionals. C # ma Nullabletypy.

O ile mogę stwierdzić, oba służą temu samemu celowi, oprócz wartości pewnego rodzaju przechowują informacje, czy zmienna ma wartość, czy jest niezdefiniowana (niezainicjowana).

Pytanie brzmi, czy są Optionalstylko Nullabletypy o różnych nazwach, czy istnieją inne różnice pojęciowe?

Innymi słowy, mówiąc o samym pojęciu, lub w kontekście języków, które nie mają Optionalslub Nullables, czy ma to znaczenie, używa się tego terminu?

Wdrażając tę ​​funkcjonalność w języku, nie ma znaczenia, czy podam typ, Optionals<T>czy teżNullable<T>

Dalija Prasnikar
źródło
Z punktu widzenia agnostyki językowej są one identyczne. To powiedziawszy, język może różnicować pojęcia (np. Czy wymuszane jest dopasowanie wzorca).
Thomas Eding,
C # mogą mieć zbyt Options (to tylko monadycznego wzorzec): github.com/louthy/language-ext
Den
2
Używanie odwołania zerowego (lub wskaźnika NULL w językach ze wskaźnikami) to hack, którego niektóre języki używają do reprezentowania wartości opcjonalnych, tj. Kontenera, który może mieć jedną wartość lub nie mieć jej wcale. Ma to ograniczenie polegające na tym, że można uznać za opcjonalny typ oparty na referencjach (lub wskaźnikach). Tak więc np. W Javie nie można uczynić liczby całkowitej opcjonalną bez zawijania jej w obiekcie (np. Liczba całkowita). Inne języki zapewniają typy opcjonalne jako typy ogólne, które mogą owijać dowolny inny typ, np. Może w Haskell, Opcja w Scali i tak dalej.
Giorgio

Odpowiedzi:

5

Istnieje inna konotacja, mimo że działają one bardzo podobnie. Wszyscy oprócz Microsoftu (wstaw tutaj rzut oka) używa nulli nullabletylko w kontekście referencji. Optionsi Maybessą ogólnie rozumiane jako odnoszące się zarówno do referencji, jak i wartości, szczególnie w funkcjonalnych językach programowania, w których przejrzystość referencyjna oznacza, że ​​nie ma dużej różnicy między wartością a referencją.

Innymi słowy, mówiąc o samej koncepcji lub w kontekście języków, które nie mają Optionalslub Nullablesczy ma znaczenie, który termin jest używany?

Optionsjest terminem, który powoduje najmniej zamieszania wśród szerokiego grona odbiorców. Tylko programiści C # będą myśleć o Nullablepotencjalnym zastosowaniu do typu wartości i myślę, że większość z nich jest przynajmniej świadoma tego, czym Optionjest.

Karl Bielefeldt
źródło
Myślę, że wszyscy oprócz Microsoftu i projektantów SQL.
Jules
9

W .NET istnieją dwie kategorie typów: odwołania i wartości (int, double, structs, enums itp.). Wśród ich różnic jest fakt, że referencja może być null, podczas gdy wartość nie. Zatem jeśli masz typ wartości i chcesz przekazać „opcjonalną” lub „nieznaną” semantykę, możesz ją ozdobić Nullable<>. Zauważ, że Nullable<>jest ograniczony przez typ, aby akceptować tylko typy wartości (ma where T : structklauzulę). Nullable<>ma również specjalne afordancje od kompilatora, dzięki którym nullwartość jest chroniona przed NullReferenceExceptions:

string x = null;
x.ToString(); // throws a NullReferenceException

int? y = null;
y.ToString(); // returns ""

W językach funkcjonalnych (takich jak Scala, F #, Haskell, Swift itp) to jest wspólne dla nullcelu nie istnieje . Jest tak, ponieważ ogólnie ludzie uważają istnienie tego nullza zły pomysł , a projektanci języków postanowili rozwiązać ten problem, nie pozwalając mu na to.

Oznacza to, że ponownie potrzebujemy jakiegoś sposobu przedstawienia nie-wartości w tych językach. Wpisz Optiontyp (nomenklatura jest różna, nazywa się Maybew Haskell). Wykonuje to podobne zadanie Nullable, ponieważ otacza typ, aby dodać przypadek, w którym wartość to „Brak” lub „Nieznany” itp.

Prawdziwa różnica polega na tym, że dodatkowe funkcje są dostępne w implementowanych językach Option. Jako przykład weź Option.map(w pseudokodzie):

function Option<T2> Option.map(opt: Option<T1>, mapFunc: T1 -> T2) {
    if (opt is None) return None
    else return Option<T2>(mapFunc(opt.Value))
}

Łańcuchowe funkcje, takie jak, Option.mapto potężny sposób na uniknięcie typowej płyty kontrolnej zerowania, którą widzisz wszędzie w C #:

if (service == null)
    return null;
var x = service.GetValue();
if (x == null || x.Property == null)
    return null;
return x.Property.Value;

Nullable równoważne w C # byłoby:

public static Nullable<T2> Map<T1, T2>(this Nullable<T1> nullable, Func<T1, T2> f)
    where T1 : struct
    where T2 : struct
{
    if (!nullable.HasValue) return (T2?)null;
    else return (T2?) f(nullable.Value);
}

Jednak ma to ograniczoną użyteczność w języku C #, ponieważ będzie działać tylko dla typów wartości.

Nowa wersja C # oferuje operator „zerowej propagacji” ( ?.), który jest podobny do Option.mapfunkcji, z tą różnicą, że ma zastosowanie tylko do metod i akcesorów właściwości. Powyższa próbka zostanie przepisana

return service?.GetValue()?.Property?.Value;
AlexFoxGill
źródło
C # jest nieczystym językiem funkcjonalnym (podobnie jak F #). Również F # ma wartości zerowe.
Den
C # 6 ma wartość NULL przymus, więc przynajmniej część kodu nie jest aktualne: github.com/dotnet/roslyn/wiki/... roslyn.codeplex.com/discussions/540883
Den
Opcje są również łatwe do wdrożenia: github.com/louthy/language-ext
Den
1
@Den: C # pochyla się w kierunku OOP, podczas gdy F # pochyla się w kierunku FP. Brak curry i zmienności domyślnie oznacza, że ​​C # nie jest odpowiedni do poważnego programowania funkcjonalnego. Na końcu odpowiedzi wspomniałem o propagacji zerowej. Opcje są rzeczywiście łatwe do zaimplementowania w języku C #, ale to odciąga od pytania.
AlexFoxGill
4
@ Den Myślę, że w twoich komentarzach jest słaby wybór słów. Nieczysty język funkcjonalny to język funkcjonalny, który umożliwia działania niepożądane. C # może mieć pewne funkcje funkcjonalne i można z nich korzystać z doskonałym skutkiem, ale nie jest to język funkcjonalny. Myślę, że miałeś na myśli, że żaden język nie jest w 100% funkcjonalny, ale F # jest bardzo zbliżony do OCaml, który pod wieloma względami jest językiem funkcjonalnym. Wszelkie odchylenia od funkcjonalnego paradygmatu w większości istnieją, więc może współpracować z obcym kodem .NET. W tym przypadku nullnie jest prawidłową wartością dla typów F #.
Doval