Qual è la differenza tra Optionals e Nullable type


15

Swift ha Optionals. C # ha Nullabletipi.

Per quanto ne so, entrambi hanno lo stesso scopo, oltre al valore di un certo tipo memorizzano le informazioni se la variabile ha valore o non è definita (non inizializzata).

La domanda è: sono Optionalssolo Nullabletipi con un nome diverso o ci sono altre differenze concettuali?

In altre parole, parlando del concetto stesso, o nel contesto di lingue che non hanno Optionalso Nullables, importa quale termine viene usato?

Quando si implementa questa funzionalità nel linguaggio, è importante che io abbia un nome Optionals<T>oNullable<T>


Dal punto di vista agnostico della lingua, sono identici. Detto questo, una lingua può differenziare i concetti (ad es. Se viene applicata la corrispondenza dei pattern).
Thomas Eding,

Anche C # può avere Opzioni (è solo un modello monadico): github.com/louthy/language-ext
Den

2
Usare un riferimento null (o un puntatore NULL, nelle lingue con puntatori) è un hack che alcune lingue usano per rappresentare valori opzionali, ovvero un contenitore che può avere un valore o nessun valore. Ciò ha la limitazione che puoi considerare facoltativo solo un tipo basato su riferimenti (o puntatori). Pertanto, ad esempio, in Java non è possibile rendere facoltativo un numero intero senza inserirlo in un oggetto (ad esempio Integer). Altre lingue forniscono tipi opzionali come tipi generici che possono avvolgere qualsiasi altro tipo, ad esempio Forse in Haskell, Opzione in Scala e così via.
Giorgio,

Risposte:


5

C'è una connotazione diversa, anche se funzionano in modo molto simile. Tutti tranne Microsoft (inserire qui il eye-roll) nulle nullablesolo nel contesto dei riferimenti. Optionse Maybessi intende generalmente riferirsi sia a riferimenti che a valori, specialmente nei linguaggi di programmazione funzionale in cui la trasparenza referenziale significa che non c'è molta differenza tra un valore e un riferimento.

In altre parole, parlare del concetto stesso, o nel contesto di lingue che non hanno Optionalso Nullables, importa quale termine viene utilizzato?

Optionsè il termine che causa la minima confusione tra un vasto pubblico. Solo i programmatori C # considereranno un Nullablepotenzialmente applicabile a un tipo di valore e penso che la maggior parte di loro sia almeno consapevole di ciò che Optionè.


Tutti tranne Microsoft e i progettisti di SQL, penso che tu intenda.
Jules,

9

In .NET, ci sono due categorie di tipo: riferimenti e valori (int, double, struct, enums ecc.). Tra le loro differenze c'è il fatto che un riferimento può essere null, mentre un valore non può. Pertanto, se si dispone di un tipo di valore e si desidera trasmettere una semantica "opzionale" o "sconosciuta", è possibile adornarlo Nullable<>. Si noti che Nullable<>è vincolato dal tipo per accettare solo i tipi di valore (ha una where T : structclausola). Nullable<>ha anche vantaggi speciali dal compilatore per cui un nullvalore è protetto da NullReferenceExceptions:

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

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

In linguaggi funzionali (come la Scala, F #, Haskell, Swift ecc) è comune per nulla non esiste . Questo perché nel complesso la gente considera l'esistenza di nulluna cattiva idea e i progettisti del linguaggio hanno deciso di affrontare questo problema impedendolo.

Ciò significa che abbiamo di nuovo bisogno di un modo per rappresentare un valore in queste lingue. Inserisci il Optiontipo (la nomenclatura varia, si chiama Maybein Haskell). Questo fa un lavoro simile a Nullablequello che avvolge un tipo per aggiungere il caso in cui il valore è "Nessuno" o "Sconosciuto" ecc.

La vera differenza sta nelle funzioni extra fornite dalle lingue che implementano Option. Ad esempio, prendi Option.map(in pseudocodice):

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

Il concatenamento di funzioni come Option.mapè un modo potente per evitare la tipica piastra di controllo null check che vedi ovunque in C #:

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

L'equivalente Nullable in C # sarebbe:

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);
}

Tuttavia, questo ha un'utilità limitata in C # perché funzionerà solo per i tipi di valore.

La nuova versione di C # offre l'operatore "null propagation" ( ?.) che è simile alla Option.mapfunzione tranne che è applicabile solo a metodi e accessori di proprietà. L'esempio sopra verrebbe riscritto

return service?.GetValue()?.Property?.Value;

C # è un linguaggio funzionale impuro (proprio come F #). Anche F # ha valori null.
Den

C # 6 ha una coercizione di valore nullo, quindi almeno parte del tuo codice non è aggiornato: github.com/dotnet/roslyn/wiki/… roslyn.codeplex.com/discussions/540883
Den

Anche le opzioni sono facili da implementare: github.com/louthy/language-ext
Den

1
@Den: C # si inclina verso OOP mentre F # si inclina verso FP. La mancanza di curry e la mutabilità per impostazione predefinita indicano che C # non è appropriato per una seria programmazione funzionale. Ho menzionato la propagazione nulla alla fine della risposta. Le opzioni sono davvero semplici da implementare in C # ma ciò si discosta dalla domanda.
AlexFoxGill

4
@ Penso che ci sia una scarsa scelta di parole nei tuoi commenti. Un linguaggio funzionale impuro è un linguaggio funzionale che consente effetti collaterali. C # può avere alcune caratteristiche funzionali e puoi usarle con grande efficacia, ma non è un linguaggio funzionale. Immagino volessi dire che nessuna delle due lingue è funzionale al 100%, ma F # è molto vicino a OCaml, che per molti versi è un linguaggio funzionale. Qualunque deviazione faccia dal paradigma funzionale, esiste per lo più in modo che possa interagire con il codice .NET esterno. Caso in questione, nullnon è un valore valido per i tipi F #.
Doval,
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.