Utilizando correctamente nulo
Hay diferentes formas de usar null
. La forma más común y semánticamente correcta es usarlo cuando puede o no tener un solo valor. En este caso, un valor es igual null
o es algo significativo como un registro de la base de datos o algo así.
En estas situaciones, generalmente lo usa así (en pseudocódigo):
if (value is null) {
doSomethingAboutIt();
return;
}
doSomethingUseful(value);
Problema
Y tiene un gran problema. ¡El problema es que para cuando invocas doSomethingUseful
el valor puede no haber sido verificado null
! Si no fuera así, el programa probablemente se bloqueará. Y es posible que el usuario ni siquiera vea ningún mensaje de error bueno, quedando con algo como "error horrible: ¡valor deseado pero nulo!" (después de la actualización: aunque puede haber incluso menos errores informativos como Segmentation fault. Core dumped.
, o peor aún, ningún error y manipulación incorrecta en nulo en algunos casos)
Olvidar escribir cheques null
y manejar null
situaciones es un error extremadamente común . Es por eso que Tony Hoare, quien inventó, null
dijo en una conferencia de software llamada QCon London en 2009 que cometió el error de mil millones de dólares en 1965:
https://www.infoq.com/presentations/Null-References-The-Billion-Dollar- Error-Tony-Hoare
Evitando el problema
Algunas tecnologías e idiomas hacen que sea null
imposible olvidar la comprobación de diferentes maneras, reduciendo la cantidad de errores.
Por ejemplo, Haskell tiene la Maybe
mónada en lugar de nulos. Supongamos que DatabaseRecord
es un tipo definido por el usuario. En Haskell, un valor de tipo Maybe DatabaseRecord
puede ser igual Just <somevalue>
o igual a Nothing
. Luego puede usarlo de diferentes maneras, pero no importa cómo lo use, no puede aplicar alguna operación Nothing
sin saberlo.
Por ejemplo, esta función llamada zeroAsDefault
devuelve x
para Just x
y 0
para Nothing
:
zeroAsDefault :: Maybe Int -> Int
zeroAsDefault mx = case mx of
Nothing -> 0
Just x -> x
Christian Hackl dice que C ++ 17 y Scala tienen sus propios modos. Por lo tanto, puede intentar averiguar si su idioma tiene algo así y usarlo.
Los nulos todavía se usan ampliamente
Si no tienes nada mejor, entonces usar null
está bien. Solo mantente atento. Las declaraciones de tipo en funciones te ayudarán de alguna manera.
Además, eso puede sonar no muy progresivo, pero debe verificar si sus colegas quieren usar null
o algo más. Pueden ser conservadores y es posible que no quieran usar nuevas estructuras de datos por algunos motivos. Por ejemplo, admitir versiones anteriores de un idioma. Tales cosas deben declararse en los estándares de codificación del proyecto y debatirse adecuadamente con el equipo.
En su propuesta
Sugiere usar un campo booleano separado. Pero debe verificarlo de todos modos y aún así puede olvidar verificarlo. Entonces no hay nada ganado aquí. Si incluso puede olvidar algo más, como actualizar ambos valores cada vez, entonces es aún peor. Si null
no se resuelve el problema de olvidar verificar, entonces no tiene sentido. Evitar null
es difícil y no debe hacerlo de tal manera que lo empeore.
Cómo no usar nulo
Finalmente, hay formas comunes de usar null
incorrectamente. Una de esas formas es usarlo en lugar de estructuras de datos vacías, como matrices y cadenas. ¡Una matriz vacía es una matriz adecuada como cualquier otra! Casi siempre es importante y útil para las estructuras de datos, que pueden ajustarse a múltiples valores, para poder estar vacías, es decir, tiene una longitud 0.
Desde el punto de vista de álgebra, una cadena vacía para cadenas es muy similar a 0 para números, es decir, identidad:
a+0=a
concat(str, '')=str
La cadena vacía permite que las cadenas en general se conviertan en un monoide:
https://en.wikipedia.org/wiki/Monoid
Si no lo obtiene, no es tan importante para usted.
Ahora veamos por qué es importante para la programación con este ejemplo:
for (element in array) {
doSomething(element);
}
Si pasamos una matriz vacía aquí, el código funcionará bien. Simplemente no hará nada. Sin embargo, si pasamos un null
aquí, es probable que tengamos un error con un error como "no se puede recorrer nulo, lo siento". Podríamos envolverlo, if
pero eso es menos limpio y, de nuevo, es posible que se olvide de verificarlo
Cómo manejar nulo
Lo que doSomethingAboutIt()
debería estar haciendo y especialmente si debería arrojar una excepción es otro tema complicado. En resumen, depende de si null
fue un valor de entrada aceptable para una tarea determinada y de lo que se espera en respuesta. Las excepciones son para eventos que no se esperaban. No profundizaré más en ese tema. Esta respuesta ya es larga.
std::optional
oOption
. En otros idiomas, es posible que tenga que construir un mecanismo apropiado usted mismo, o en realidad puede recurrir anull
algo similar porque es más idiomático.