voto votar qué quien que porque pasa nulo impugnado gana favorece entre diferencia con como blanco anular f# null nullpointerexception

f# - votar - ¿Nadie es menos malo que nulo?



voto en blanco y voto nulo (4)

En F # es muy importante que no tengan valores nulos y no quieran admitirlo. Aún así, el programador tiene que hacer casos para Ninguno similar a los programadores de C # que tienen que verificar! = Nulo.

¿Nadie es realmente menos malo que nulo?

Mientras que null introduce las posibles fuentes de error en tiempo de ejecución ( NullRefereceException ) cada vez que elimine la referencia a un objeto en C #, None obliga a hacer que las fuentes de error en tiempo de ejecución sean explícitas en F #.

Por ejemplo, al invocar GetHashCode en un objeto dado, C # inyecta silenciosamente una fuente de error en tiempo de ejecución:

class Foo { int m; Foo(int n) { m=n; } int Hash() { return m; } static int hash(Foo o) { return o.Hash(); } };

En contraste, se espera que el código equivalente en F # esté libre de null :

type Foo = { m: int } member foo.Hash() = foo.m let hash (o: Foo) = o.Hash()

Si realmente quisiera un valor opcional en F #, entonces usaría el tipo de option y debe manejarlo explícitamente o el compilador dará una advertencia o error:

let maybeHash (o: Foo option) = match o with | None -> 0 | Some o -> o.Hash()

Aún puede obtener NullReferenceException en F # al sortear el sistema de tipos (que se requiere para la interoperabilidad):

> hash (box null |> unbox);; System.NullReferenceException: Object reference not set to an instance of an object. at Microsoft.FSharp.Core.LanguagePrimitives.IntrinsicFunctions.UnboxGeneric[T](Object source) at <StartupCode$FSI_0021>.$FSI_0021.main@() Stopped due to error

En F # es muy importante que no tengan valores nulos y no quieran admitirlo. Aún así, el programador tiene que hacer casos para Ninguno similar a los programadores de C # que tienen que verificar! = Nulo.

¿Nadie es realmente menos malo que nulo?


¡Por supuesto que es menos malvado!

Si no marca contra Ninguno, en la mayoría de los casos tendrá un error de tipo en su aplicación, lo que significa que no se compilará, por lo que no se puede bloquear con una NullReferenceException (ya que Ninguno se traduce en nulo).

Por ejemplo:

let myObject : option<_> = getObjectToUse() // you get a Some<''T>, added explicit typing for clarity match myObject with | Some o -> o.DoSomething() | None -> ... // you have to explicitly handle this case

Todavía es posible lograr un comportamiento similar a C #, pero es menos intuitivo, ya que tiene que decir explícitamente "ignorar que esto puede ser Ninguno":

let o = myObject.Value // throws NullReferenceException if myObject = None

En C #, no está obligado a considerar que su variable es nula, por lo que es posible que simplemente se olvide de realizar una comprobación. Mismo ejemplo que el anterior:

var myObject = GetObjectToUse(); // you get back a nullable type myObject.DoSomething() // no type error, but a runtime error

Edit : Stephen Swensen tiene toda la razón, mi código de ejemplo tenía algunos defectos, lo estaba escribiendo a toda prisa. Fijo. ¡Gracias!


Digamos que te muestro una definición de función como esta:

val getPersonByName : (name : string) -> Person

¿Qué crees que sucede cuando pasas el name de una persona que no existe en el almacén de datos?

  • ¿La función lanza una excepción NotFound?
  • ¿Vuelve nulo?
  • ¿Crea la persona si no existe?

Aparte de leer el código (si tiene acceso a él), leer la documentación (si alguien tuvo la amabilidad de escribirlo) o simplemente llamar a la función, no tiene forma de saberlo. Y ese es básicamente el problema con los valores nulos: se ven y actúan como valores no nulos, al menos hasta el tiempo de ejecución.

Ahora digamos que tienes una función con esta firma en su lugar:

val getPersonByName : (name : string) -> option<Person>

Esta definición hace que sea muy explícito lo que sucede: o recuperarás a una persona o no, y este tipo de información se comunica en el tipo de datos de la función. Por lo general , tiene una mejor garantía de manejar ambos casos de un tipo de opción que un valor potencialmente nulo.

Yo diría que los tipos de opciones son mucho más benévolos que los nulos.


El problema con null es que tiene la posibilidad de usarlo en casi todas partes , es decir, introducir estados inválidos donde esto no es intencional ni tiene sentido .

Tener una ''a option siempre es una cosa explícita. Usted declara que una operación puede producir Some valores significativos o None , que el compilador puede exigir que se verifique y procese correctamente.

Al desalentar a null en favor de un ''a option tipo de ''a option , básicamente tiene la garantía de que cualquier valor en su programa es de alguna manera significativo. Si algún código está diseñado para funcionar con estos valores, no puede simplemente pasar los que no son válidos, y si existe una función de tipo- option , tendrá que cubrir todas las posibilidades.