2009-06-03 16 views

Respuesta

28

No me gusta particularmente la respuesta que he escrito a continuación, porque creo que el lector la verá como 'predicando al coro' o como 'una tontería compleja', pero he decidido publicar de todos modos, en caso de que invite a comentarios fructíferos-discusión.

En primer lugar, puede ser digno de mención que entender que

let x : string option = Some(null) 

es un valor válido, que indica la presencia (en vez de la ausencia) de un valor (algunos más que ninguno), pero el valor en sí es nulo. (El significado de un valor tal que dependerá del contexto.)

Si usted está buscando lo que veo como el modelo 'correcto' mental, que es algo como esto ...

Toda la noción de que "todos los tipos de referencia admiten un valor 'nulo'" es uno de los mayores y más costosos errores de .Net y CLR. Si hoy se reescribió la plataforma desde cero, creo que la mayoría de la gente está de acuerdo en que las referencias no se pueden anular por defecto, y usted necesitaría un mecanismo explícito para optar por nulo. Tal como está hoy, hay cientos, sino miles de API que toman, por ejemplo, "string foo" y no quiere un nulo (por ejemplo, arrojaría ArgumentNullException si pasaba null). Claramente esto es algo mejor manejado por un sistema de tipo. Idealmente, 'cadena' significaría 'no nulo', y para la minoría de APIs que do quieren nula, se escribe eso a cabo, por ejemplo, "Nullable < cadena> foo" o "Opción < cadena> foo" o lo que sea. Entonces, es la plataforma .Net existente la que es el 'bicho raro' aquí.

Muchos lenguajes funcionales (como ML, una de las principales influencias de F #) lo han sabido siempre, por lo que diseñaron sus sistemas tipo 'derecho', donde si quiere admitir un valor 'nulo', usa un constructor de tipo genérico para señalar explícitamente datos que intencionalmente pueden tener 'asbence of a value' como valor legal. En ML, esto se hace con el tipo "t opción" - 'opción' es una solución fina y de propósito general para este problema. El núcleo de F # es compatible (compilaciones cruzadas) con OCaml, un dialecto ML, y así F # hereda este tipo de su ascendencia ML.

Pero F # también tiene que integrarse con el CLR, y en el CLR, todas las referencias puede ser nulo.F # intenta caminar una línea algo bien, en el que puede definir nuevos tipos de clases en C#, y para aquellos tipos, F # se comportará ML-como (y no es fácil admitir null como un valor):

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

embargo el mismo tipo definido en un conjunto C# admitirá nulo como un valor adecuado en F #. (Y F # permite aún una puerta trasera:.

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

para conseguir eficacia en todo el sistema F # tipo normal y acceder al CLR directamente)

Todo esto está empezando a sonar complicado, pero básicamente el sistema de F # te permite programar un montón de F # en el estilo 'ML', donde nunca tendrás que preocuparte por null/NferentReferenceExceptions, porque el sistema de tipos te impide hacer las cosas incorrectas aquí. Pero F # tiene que integrarse muy bien con .Net, por lo que todos los tipos que se originan en código no F (como 'cadena') todavía admiten valores nulos, por lo que cuando programe con esos tipos, debe programar tan defensivamente como lo hace normalmente. el CLR. Con respecto a nulo, efectivamente F # proporciona un refugio donde es fácil hacer 'programación sin nulo, de la manera que Dios lo pensó', pero al mismo tiempo interoperar con el resto de .Net.

No he respondido realmente a su pregunta, pero si sigue mi lógica, entonces no haría la pregunta (o no lo haría, al estilo de Joshu de "Godel, Escher, Bach").

+1

No tenía que ser así. Podrían haber mapeado funciones CLR a "opción " en lugar de "Cadena" a menos que estuvieran marcadas como nunca devuelven nulo. Y en .NET 4, se supone que las funciones deben estar marcadas como tales. –

+0

Me gusta esta respuesta, un gran valor agregado para StackOverflow. – Benjol

+1

Si tan solo pudiera dar respuestas 'favoritas'. Ah bueno. Anywho, si hicieran eso, Grauren, tendríamos una pesadilla de un patrón de tiempo que coincidiera con cada 'opción' que el marco escupiera. Afortunadamente, no hay tantas funciones que puedan devolver valores nulos, por lo que no tiene que ser demasiado cauteloso. – YotaXP

4

Creo que se podría reclasificar esto como una cuestión más general

¿Cuál es la diferencia entre la opción de tipo de referencia al azar y sólo un tipo ref aleatoria

La diferencia es con una opción, están proporcionando un caso de valor vacío explícito. Es una manera declarativa de decir "No puedo proporcionar un valor". Una opción de valor Ninguno representa inequívocamente la falta de un valor.

Muchas veces las personas usan null para representar la falta de un valor. Desafortunadamente, esto es ambiguo para el lector casual porque se desconoce si null representa un valor válido o la falta de un valor. La opción elimina esta ambigüedad.

+0

¿Cómo elimina la ambigüedad? Desde donde estoy sentado no hay diferencia entre vincular un valor nulo a una variable y vincular un valor nulo a una variable. –

+0

@Grauenwolf el problema es nulo a menudo es un valor válido no vacío. Sin embargo, la opción se entiende como un "no tengo valor" explícito. Creo que la mejor manera de entender la diferencia es considerar que es posible tener una opción con un valor Some de null. – JaredPar

+0

Así que ahora tenemos que verificar tanto los nulos de estilo Ninguno como los nulos de estilo nulo? Esto no es divertido –

Cuestiones relacionadas