then question operator mark c# .net performance clr type-systems

question - null c#



¿Por qué null existe en.NET? (11)

Bueno, los valores (valor-tipo vars) solo pueden ser null ya que los tipos anulables se introdujeron en Fx2.

Pero supongo que te refieres a:

¿Por qué las referencias pueden ser null ?

Eso es parte de la utilidad de las referencias. Considere un árbol o LinkedList, no serían posibles (no pueden finalizar) sin null .

Podría proponer muchos más ejemplos, pero existe principalmente null para modelar el concepto de propiedades / relaciones "opcionales".

¿Por qué los valores pueden ser nulos en .NET? ¿Es esto superior a tener una garantía en la que todo tenga un valor y que nada sea nulo?

¿Alguien sabe cómo se llama cada una de estas metodologías?

De cualquier forma, no estoy muy bien informado sobre esto, pero no tendría un valor para todo lo que facilita las cosas, en términos de simplicidad, es decir, eliminando los controles nulos, y pudiendo escribir algoritmos más simplificados que no tienen que ramificarse para cheques

¿Cuáles son los pros y los contras de cada estilo en términos de rendimiento, simplicidad, paralelismo, a prueba de futuro, etc.


Esto me recuerda un episodio de la serie "Connections" de James Burke, donde los monjes transcribían árabe al latín y primero encontraron un dígito cero. La aritmética romana no tenía una representación para cero, pero sí la aritmética árabe / aramea. "¿Por qué tenemos que escribir una carta para indicar nada?" argumentaron los monjes católicos. "¡Si no es nada, no debemos escribir nada!"

Afortunadamente para la sociedad moderna, perdieron la discusión y aprendieron a escribir cero dígitos en sus matemáticas. ;>

Null simplemente representa la ausencia de un objeto. Hay lenguajes de programación que no tienen "nulo" per se, pero la mayoría de ellos todavía tienen algo para representar la ausencia de un objeto legítimo. Si tira "nulo" y lo reemplaza con algo llamado "EmptyObject" o "NullNode", sigue siendo un nulo solo con un nombre diferente.

Si elimina la capacidad de un lenguaje de programación para representar una variable o un campo que no hace referencia a un objeto legítimo, es decir, requiere que cada variable y campo siempre contenga una instancia de objeto válida y verdadera, entonces puede hacer que sea muy útil y eficiente las estructuras de datos son incómodas e ineficientes, como la creación de una lista vinculada. En lugar de usar un nulo para indicar el final de la lista enlazada, el programador se ve obligado a inventar instancias de objetos "falsos" para que sirvan como terminales de lista que no hacen más que indicar "no hay nada aquí".

Profundizando en el existencialismo aquí, pero: si puedes representar la presencia de algo, ¿entonces no existe una necesidad fundamental de poder representar la ausencia de él también?


Mucha gente probablemente no puede entender la codificación sin nulos, y si C # no tiene valores nulos, dudo que se haya propagado en la medida en que lo haya hecho.

Dicho esto, una buena alternativa sería, si desea permitir una referencia que pueda contener nulos, entonces la referencia debería ser explícitamente anulable, como con los tipos de valores.

Por ejemplo,

Person? person = SearchForPersonByFirstName("Steve"); if (person.HasValue) { Console.WriteLine("Hi, " + person.Value.FullName); }

Lamentablemente, cuando salió C # 1.0, no existía el concepto de Nullable; que se agregó en C # 2.0. Forzar referencias para tener valores habría roto los programas anteriores.


Ok, ahora envuelve la palabra mágica de C # -sin-null

class View { Model model; public View(Model model) { Console.WriteLine("my model : {0}, thing : {1}", this.model, this.model.thing); this.model = model; } }

¿Qué está impreso en la consola?

  • No se lanza ninguna excepción sobre el acceso a un objeto no inicializado: Ok, llame a esto una NullReferenceException y ese es el mundo actual.
  • No se compila, el usuario debe especificar un valor al declarar el modelo, ver el último punto, ya que crea el mismo resultado.
  • Algunos predeterminados para el modelo y algunos predeterminados para la cosa: Ok antes con null, al menos teníamos una manera de saber si una instancia era correcta ahora que el compilador genera imágenes similares extrañas que no contienen nada pero que aún no son válidas como modelo objetos...
  • Algo definido por el tipo de objetos: mejor podríamos definir un estado inválido específico por objeto, pero ahora cada objeto que podría ser no válido debe implementarlo independientemente junto con una forma de identificar este estado por la persona que llama ...

Así que, básicamente, para mí no parece resolver nada para eliminar un estado nulo, ya que el estado posiblemente no válido todavía necesita ser administrado de todos modos ...

Oh, compra la forma en que sería el valor predeterminado de una interfaz? Ah, y una clase abstracta ¿qué pasaría cuando se invoca un método en un valor predeterminado que se define en la clase abstracta pero que llama a otro método que es abstracto? .... .... ¿Por qué? ¿Por qué complicar el modelo a cambio de nada? ¡Es una cuestión de herencia múltiple otra vez!

Una solución sería cambiar la sintaxis por completo para obtener una completamente funcional donde el mundo nulo no salga, solo Maybes cuando quieras que exista ... Pero no es un lenguaje parecido a C y el multi-paradigma-ness de .Net se perdería.

Lo que podría faltar es un operador de propagación nula capaz de devolver nulo al modelo. ¿Cuándo el modelo es nulo, como el model.?.Thing

Ah, y para siempre, una respuesta a su pregunta:

  • La biblioteca de clases actual evolucionó después de la debacle de Microsoft-Java y C # se compiló como una "mejor Java", por lo que cambiar el tipo de sistema para eliminar referencias nulas habría sido un gran cambio. ¡Ya lograron introducir tipos de valores y eliminaron el boxeo manual!
  • Como la introducción del tipo de valor show microsoft piensa mucho acerca de la velocidad ... El hecho de que el valor predeterminado para todos los tipos se asigne a un relleno cero es realmente importante para la inicialización rápida de matrices, por ejemplo. De lo contrario, la inicialización de matrices de valores de referencia habría necesitado una amenaza especial.
  • Sin la interoperabilidad nula con C no habría sido posible, al menos en el nivel de MSIL y en el bloque inseguro deben poder sobrevivir.
  • Microsoft quería usar el framework para eliminar VB6 ++. Nothing como se llama en VB habría cambiado radicalmente el lenguaje, ya les tomó años a los usuarios cambiar de VB6 a VB.Net, tal cambio de paradigma podría haber sido fatal para el lenguaje.

Para denotar el concepto de la nada, ya que 0 no es el ajuste correcto.

Ahora puede asignar un valor Nulo a cualquier tipo de valor definiendo un tipo que admite nulos.

Creo que no podemos tener siempre un valor para la variable porque, al principio, tenemos que asignarle un valor predeterminado, y aquí viene la pregunta de por qué un valor específico se aprovecha de los demás.


Pasas histéricas

Es una resaca de los lenguajes de nivel C donde vives con la manipulación explícita del puntero. Los lenguajes declarativos modernos (Mercury, Haskell, OCaml, etc.) pasan muy felizmente sin nulos. Allí, cada valor tiene que ser construido explícitamente. La idea ''nula'' se maneja a través de los tipos ''opción'', que tienen dos valores, ''no'' (correspondiente a nulo) y ''sí (x)'' (correspondiente a no nulo con valor x). Debe descomprimir cada valor de opción para decidir qué hacer, por lo tanto: no hay errores de referencia de puntero nulo.

No tener nulos en un idioma te ahorra tanto dolor, realmente es una pena que la idea aún persista en los lenguajes de alto nivel.


Tampoco estoy familiarizado con las alternativas, pero no veo una diferencia entre Object.Empty y null, que no sea null, te permite saber que algo está mal cuando tu código intenta acceder al objeto, mientras que Object.Empty permite procesarlo continuar. A veces quieres un comportamiento, y a veces quieres el otro. Distinguir null de Empty es una herramienta útil para eso.


Tan atractivo como es un mundo sin null , presenta muchas dificultades para muchos patrones y construcciones existentes. Por ejemplo, considere los siguientes constructos que necesitarían cambios importantes si null no existiera

  1. Crear una matriz de tipos de referencia ala: new object[42] . En el mundo de CLR existente, las matrices se llenarían con null que es ilegal. La semántica Array debería cambiar bastante aquí
  2. Hace que el default(T) útil solo cuando T es un tipo de valor. Su uso en tipos de referencia o genéricos no restringidos no estaría permitido
  3. Los campos en una estructura que son un tipo de referencia deben ser rechazados. Un tipo de valor puede inicializarse 0 hoy en el CLR, lo que convenientemente llena los campos de tipos de referencia con null . Eso no sería posible en un mundo no nulo, por lo tanto, los campos cuyo tipo son tipos de referencia en struct deberían ser desautorizados

Ninguno de los problemas anteriores es irresoluble, pero da lugar a cambios que realmente desafían la forma en que los desarrolladores tienden a pensar sobre la codificación. Personalmente, desearía que C # y .Net se diseñen con la eliminación de nulos, pero desafortunadamente no lo era y me imagino que problemas como los anteriores tuvieron algo que ver con eso.


Tenemos que agradecer a Tony Hoare , uno de los primeros pioneros que trabajó en Algol. Él más bien lo lamenta:

Lo llamo mi error billonario. Fue la invención de la referencia nula en 1965. En ese momento, estaba diseñando el primer sistema de tipo completo para referencias en un lenguaje orientado a objetos (ALGOL W). Mi objetivo era garantizar que todo el uso de las referencias sea absolutamente seguro, con una verificación realizada automáticamente por el compilador. Pero no pude resistir la tentación de poner una referencia nula, simplemente porque era muy fácil de implementar. Esto ha llevado a innumerables errores, vulnerabilidades y fallas en el sistema, que probablemente hayan causado mil millones de dolores y daños en los últimos cuarenta años.

Mil millones es un número de baja bola, creo.


Yo especulo que su existencia es null en .NET porque (C #) siguió en los pasos de C ++ / Java (y solo ha comenzado a ramificarse en versiones más recientes) y VB / J ++ (que se convirtió en VB.NET/J#) ya tenía la noción de valores de "nada", es decir, .NET tiene null por lo que era y no por lo que podría haber sido.

En algunos idiomas no existe la noción de null : null puede reemplazarse por completo con un tipo como Quizás: hay Algo (el objeto) o Nada (¡pero esto no es null ! No hay forma de sacar el "Nada" de un Tal vez! )

En Scala con opción:

val opt = Some("foo") // or perhaps, None opt match { case Some(x) => x.toString() // x not null here, but only by code-contract, e.g. Some(null) would allow it. case _ => "nothing :(" // opt contained "Nothing" }

Esto se hace por el diseño del lenguaje en Haskell ( null no es posible ... ¡en absoluto!) Y por el soporte de la biblioteca y el uso cuidadoso como en Scala, como se muestra arriba. (Scala admite null , posiblemente para la interoperabilidad Java / C #, pero es posible escribir el código Scala sin utilizar este hecho, a menos que se permita la "fuga" de null ).

Editar: Vea Scala: Patrón de opciones , Scala: opción Cheat Cheet y SO: Use Maybe Type en Haskell . La mayoría de las veces, hablar de Tal vez en Haskell plantea el tema de las Mónadas. No pretendo entenderlos, pero aquí hay un enlace junto con el uso de Maybe .

Feliz codificación.


null es solo el nombre del valor predeterminado para un tipo de referencia. Si no se permitiera null , entonces el concepto de "no tiene un valor" no desaparecería, solo lo representarías de una manera diferente. Además de tener un nombre especial, este valor predeterminado también tiene una semántica especial en el caso de que se use incorrectamente, es decir, si lo trata como si hubiera un valor, cuando de hecho no existe.

Si no hubiera null :

  1. Debería definir valores centinela predeterminados para que los usen sus tipos cuando "no hay ningún valor". Como un ejemplo trivial, considere el último nodo de una lista de enlaces simples hacia adelante.
  2. Debería definir la semántica para las operaciones realizadas en todos estos valores centinelas.
  3. El tiempo de ejecución tendría una sobrecarga adicional para manejar los valores centinelas. En las máquinas virtuales modernas como las utilizadas por .NET y Java, no existe una sobrecarga para la verificación nula antes de la mayoría de las llamadas a funciones y las desreferencias porque la CPU proporciona formas especiales de manejar este caso, y la CPU está optimizada para casos donde las referencias no son nulas (p. ej., predicción de bifurcación).

En resumen:

  • El nombre cambiaría, pero el concepto no cambiaría.
  • La carga de definir y comunicar el valor predeterminado y la semántica para los casos en los que no tiene "valor" se coloca en los desarrolladores y la documentación del desarrollador.
  • El código que se ejecuta en las máquinas virtuales modernas enfrentaría la hinchazón del código y la degradación sustancial del rendimiento de muchos algoritmos.

Los problemas con null descritos por Tony Hoare suelen deberse al hecho de que, antes de las máquinas virtuales modernas, los sistemas de tiempo de ejecución no tenían un manejo tan claro de null valores null usados ​​como los que tiene hoy en día. El uso incorrecto de punteros / referencias sigue siendo un problema, pero rastrear el problema cuando se trabaja con .NET o Java tiende a ser mucho más fácil de lo que solía ser, por ejemplo, C.