2009-06-03 14 views

risposta

28

Non mi piace particolarmente la risposta che ho digitato di seguito, perché penso che il lettore lo vedrà come "predica al coro" o come "qualche assurdità complessa", ma ho deciso di postare in ogni caso, nel caso in cui invita fruttuosi commenti-discussione.

Prima di tutto, può essere notevole capire che

let x : string option = Some(null) 

è un valore valido, che indica la presenza (anziché assenza) di un valore (Alcuni anziché Nessuno), ma il valore è di per sé nullo. (Il significato di tale valore dipenderebbe dal contesto.)

Se siete alla ricerca di quello che vedo come il modello mentale 'giusto', va qualcosa di simile ...

L'intero concetto che "tutti i tipi di riferimento ammettono un valore" null "è uno degli errori più grandi e costosi di .Net e CLR. Se la piattaforma fosse stata ridefinita da zero oggi, penso che la maggior parte delle persone concorda sul fatto che i riferimenti non sono annullabili per impostazione predefinita e che occorrerebbe un meccanismo esplicito per l'attivazione di null. Così com'è oggi, ci sono centinaia, se non migliaia di API che prendono ad es. "string foo" e non voglio un valore nullo (ad es. genererebbe ArgumentNullException se hai passato null). Chiaramente questo è qualcosa di meglio gestito da un sistema di tipi. Idealmente, "stringa" significherebbe "non null" e per la minoranza di API che do desidera null, lo si scrive, ad es. "Nullable < string> pippo" o "Opzione < string> pippo" o qualsiasi altra cosa. Quindi è la piattaforma .Net esistente che è lo "strano" qui.

Molti linguaggi funzionali (come ML, una delle influenze principali di F #) lo hanno sempre saputo, e quindi hanno progettato i loro sistemi di tipi 'giusti', dove se si desidera ammettere un valore 'nullo', si usa un costruttore di tipi generici per segnalare esplicitamente dati che possono avere intenzionalmente 'asbence di un valore' come valore legale. In ML, questo è fatto con il tipo "t opzione" - "opzione" è una soluzione fine e generica a questo problema. Il nucleo di F # è compatibile (cross-compile) con OCaml, un dialetto ML, e quindi F # eredita questo tipo dal suo antenato ML.

Ma F # deve anche integrarsi con il CLR, e nel CLR, tutti i riferimenti possono essere nulli.F # tenta di camminare una linea un po 'bene, in quanto è possibile definire nuovi tipi di classi in F #, e per quei tipi, F # si comporterà ML-simile (e non facilmente ammettere nulla come valore):

type MyClass() = class end 
let mc : MyClass = null // does not compile 

tuttavia lo stesso tipo definito in un assembly C# ammetterà null come valore corretto in F #. (E F # consente ancora un back-door:.

let mc : MyClass = Unchecked.defaultof<_> // mc is null 

per ottenere in modo efficace in tutto il normale sistema di F # tipo e accedere direttamente al CLR)

Questo è tutto cominciando a sembrare complicato, ma in fondo il sistema F # ti consente di programmare moltissimo F # nello stile 'ML', dove non devi mai preoccuparti di null/NullReferenceExceptions, perché il sistema di tipi ti impedisce di fare le cose sbagliate qui. Ma F # deve integrarsi bene con .Net, quindi tutti i tipi che provengono dal codice non F # (come 'string') continuano ad ammettere valori nulli, e quindi quando si programma con quei tipi si deve ancora programmare in modo difensivo come si fa normalmente il CLR. Riguardo a null, in effetti F # offre un rifugio dove è facile fare 'programmare senza nulla, come Dio ha voluto', ma allo stesso tempo interagire con il resto di .Net.

Non ho davvero risposto alla tua domanda, ma se segui la mia logica, allora non avresti fatto la domanda (o non l'avrei annullata, la MU di La Joshu da "Godel, Escher, Bach").

+1

Non doveva essere in questo modo. Potrebbero aver mappato le funzioni CLR in "opzione " anziché "String" a meno che non siano state contrassegnate come non restituiscono mai nulla. E in .NET 4, le funzioni dovrebbero essere contrassegnate come tali. –

+0

Mi piace questa risposta, un sacco di valore aggiunto per StackOverflow. – Benjol

+1

Se solo potessi risposte "preferite". Ah bene. Qualunque cosa, se lo facessero, Grauren, avremmo un modello da incubo di tempo corrispondente a ogni 'opzione' che il framework sputa. Per fortuna, non ci sono molte funzioni che possono restituire valori nulli, quindi non devi essere troppo cauto. – YotaXP

4

Penso che si potrebbe riclassificare questo come una questione più generale

Qual è la differenza tra l'opzione di tipo ref casuale e solo un tipo Rif casuale

La differenza è con un'opzione, è stanno fornendo un caso di valore vuoto esplicito. È un modo dichiarativo di dire "potrei non fornire un valore". Un'opzione di valore Nessuna rappresenta in modo inequivocabile la mancanza di un valore.

Spesso le persone utilizzano null per rappresentare la mancanza di un valore. Sfortunatamente questo è ambiguo per il lettore casuale perché è sconosciuto se null rappresenta un valore valido o la mancanza di un valore. L'opzione rimuove questa ambiguità.

+0

Come rimuovere l'ambiguità? Da dove sono seduto non vi è alcuna differenza tra l'associazione di un valore nullo a una variabile e l'associazione di nessuno a una variabile. –

+0

@Grauenwolf il problema è nullo è spesso un valore non vuoto valido. L'opzione però è intesa come un esplicito "non ho alcun valore". Penso che il modo migliore per capire la differenza è considerare che è possibile avere un'opzione con un valore Some di null. – JaredPar

+0

Quindi ora controlliamo sia i nulli di tipo Nessuno che i null di stile Null? Questo non è divertente –

Problemi correlati