¿Cuál es la diferencia entre las opciones y el tipo anulable?

15

Swift tiene Optionals. C # tiene Nullabletipos.

Por lo que puedo decir, ambos sirven para el mismo propósito, además del valor de algún tipo, almacenan información si la variable tiene valor o no está definida (no inicializada).

Pregunta ¿son Optionalssólo Nullabletipos con diferente nombre o hay otras diferencias conceptuales?

En otras palabras, hablando del concepto en sí mismo, o en el contexto de lenguajes que no tienen Optionalso Nullables, ¿importa qué término se usa?

Al implementar esa funcionalidad en el idioma, ¿importa si nombre el tipo Optionals<T>oNullable<T>

Dalija Prasnikar
fuente
Desde el punto de vista agnóstico del lenguaje, son idénticos. Dicho esto, un lenguaje puede diferenciar los conceptos (por ejemplo, si se aplica o no la coincidencia de patrones).
Thomas Eding
C # también puede tener opciones (es solo un patrón monádico): github.com/louthy/language-ext
Den
2
El uso de una referencia nula (o un puntero NULL, en idiomas con punteros) es un truco que algunos idiomas usan para representar valores opcionales, es decir, un contenedor que puede tener un valor o ningún valor. Esto tiene la limitación de que solo puede considerar opcional un tipo que se basa en referencias (o punteros). Entonces, por ejemplo, en Java no puede hacer que un entero sea opcional sin envolverlo en un objeto (por ejemplo, Entero). Otros idiomas proporcionan tipos opcionales como tipos genéricos que pueden envolver cualquier otro tipo, por ejemplo, Quizás en Haskell, Opción en Scala, etc.
Giorgio

Respuestas:

5

Hay una connotación diferente, a pesar de que funcionan de manera muy similar. Todos menos Microsoft (inserte aquí el rollo de ojo) usa nully nullablesolo en el contexto de referencias. Optionsy Maybesgeneralmente se entiende que se refieren tanto a referencias como a valores, especialmente en lenguajes de programación funcionales donde la transparencia referencial significa que no hay mucha diferencia entre un valor y una referencia.

En otras palabras, hablando del concepto mismo, o en el contexto de lenguajes que no tienen Optionalso Nullables, ¿importa qué término se usa?

Optionses el término que causa la menor confusión entre una audiencia amplia. Solo los programadores de C # pensarán Nullableque a se aplica potencialmente a un tipo de valor, y creo que la mayoría de ellos son al menos conscientes de lo que Optiones un .

Karl Bielefeldt
fuente
Todos menos Microsoft y los diseñadores de SQL, creo que te refieres.
Jules
9

En .NET, hay dos categorías de tipo: referencias y valores (int, double, structs, enums, etc.). Entre sus diferencias está el hecho de que una referencia puede ser null, mientras que un valor no puede. Por lo tanto, si tiene un tipo de valor y desea transmitir una semántica "opcional" o "desconocida", puede adornarlo con Nullable<>. Tenga en cuenta que Nullable<>está restringido por tipo para aceptar solo tipos de valor (tiene una where T : structcláusula). Nullable<>también tiene ventajas especiales del compilador por las cuales un nullvalor está protegido de NullReferenceExceptions:

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

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

En lenguajes funcionales (como Scala, F #, Haskell, Swift, etc.) es común nullque no exista . Esto se debe a que, en general, las personas consideran que la existencia nulles una mala idea , y los diseñadores de idiomas han decidido abordar este problema rechazándolo.

Esto significa que nuevamente necesitamos alguna forma de representar un no valor en estos idiomas. Ingrese el Optiontipo (la nomenclatura varía, se llama Maybeen Haskell). Esto hace un trabajo similar al Nullableenvolver un tipo para agregar el caso donde el valor es "Ninguno" o "Desconocido", etc.

La verdadera diferencia está en las funciones adicionales que le dan los idiomas que implementan Option. Como ejemplo, tome Option.map(en pseudocódigo):

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

El encadenamiento de funciones Option.mapes una forma poderosa de evitar la típica repetitiva de verificación nula que se ve en todas partes en C #:

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

El equivalente anulable en C # sería:

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

Sin embargo, esto tiene una utilidad limitada en C # porque solo funcionará para los tipos de valor.

La nueva versión de C # ofrece el operador de "propagación nula" ( ?.), que es similar a la Option.mapfunción, excepto que solo es aplicable para métodos y accesores de propiedades. La muestra anterior sería reescrita

return service?.GetValue()?.Property?.Value;
AlexFoxGill
fuente
C # es un lenguaje funcional impuro (al igual que F #). También F # tiene valores nulos.
Den
C # 6 tiene una coerción de valor nulo, por lo que al menos parte de su código no está actualizado: github.com/dotnet/roslyn/wiki/… roslyn.codeplex.com/discussions/540883
Den
También las opciones son fáciles de implementar: github.com/louthy/language-ext
Den
1
@Den: C # se inclina hacia OOP mientras que F # se inclina hacia FP. La falta de curry y mutabilidad por defecto significa que C # no es apropiado para una programación funcional seria. Mencioné la propagación nula al final de la respuesta. De hecho, las opciones son simples de implementar en C #, pero eso se desvía de la pregunta.
AlexFoxGill
44
@ Den Creo que hay una mala elección de palabras en tus comentarios. Un lenguaje funcional impuro es un lenguaje funcional que permite efectos secundarios. C # puede tener algunas características funcionales y puede usarlas con gran efecto, pero no es un lenguaje funcional. Supongo que querías decir que ninguno de los dos idiomas es 100% funcional, pero F # está muy cerca de OCaml, que, según la mayoría de las cuentas, es un lenguaje funcional. Cualesquiera que sean las desviaciones que hace del paradigma funcional, existen principalmente para que pueda interoperar con el código externo .NET. Caso en cuestión, nullno es un valor válido para los tipos de F #.
Doval