Últimamente he tenido un pequeño debate con un compañero de trabajo. Estamos utilizando específicamente C #, pero esto podría aplicarse a cualquier lenguaje con tipos anulables. Digamos, por ejemplo, que tiene un valor que representa un máximo. Sin embargo, este valor máximo es opcional. Sostengo que un número anulable sería preferible. Mi compañero de trabajo favorece el uso de cero, citando precedentes. Por supuesto, cosas como los sockets de red a menudo han usado cero para representar un tiempo de espera ilimitado. Si escribiera código que tratara con sockets hoy, personalmente usaría un valor anulable, ya que siento que representaría mejor el hecho de que NO hay tiempo de espera.
¿Qué representación es mejor? Ambos requieren una comprobación de condición para el valor que significa "ninguno", pero creo que un tipo anulable transmite la intención un poco mejor.
fuente
Respuestas:
Considerar:
Idioma,
Marco de referencia,
Contexto.
1. Idioma
Usar ∞ puede ser una solución para un máximo.
JavaScript, por ejemplo, tiene un infinito. C # no.
Ada, por ejemplo, tiene rangos. C # no lo hace.
En C #, la hay
int.MaxValue
, pero no puede usarla en su caso.int.MaxValue
es el número entero máximo, 2,147,483,647. Si en su código, tiene un valor máximo de algo, como una presión máxima aceptada antes de que algo explote, usar 2,147,483,647 no tiene sentido.2. Marco
.NET Framework es bastante inconsistente en este punto, y su uso de valores mágicos puede ser criticado.
Por ejemplo,
"Hello".IndexOf("Z")
devuelve un valor mágico-1
. Tal vez hace que sea más fácil (¿verdad?) Manipular el resultado:en lugar de usar una estructura personalizada:
pero no es intuitivo en absoluto. ¿Por qué
-1
y no-123
? Un principiante también puede pensar erróneamente que eso0
significa "No encontrado" o simplemente escribir mal(position >= 0)
.3. Contexto
Si su código está relacionado con los tiempos de espera en los sockets de red, no es una mala idea usar algo que fue utilizado por todos durante décadas para ser coherente . Especialmente,
0
para un tiempo de espera es muy claro: es un valor que no puede ser cero. Usar una clase personalizada en este caso puede hacer que las cosas sean más difíciles de entender:Duration
a 0 siIsTimeoutEnabled
es cierto?IsTimeoutEnabled
es falso, ¿qué sucede si configuroDuration
a 100?Esto puede conducir a múltiples errores. Imagine la siguiente pieza de código:
La operación se ejecuta durante diez segundos. ¿Puedes ver lo que está mal con este código, sin leer la documentación de la
Timeout
clase?Conclusión
null
expresa bien la idea de que el valor no está aquí. No está provisto. No disponible. No es un número, ni una cadena cero / vacía, ni nada. No lo use para valores máximos o mínimos.int.MaxValue
está fuertemente relacionado con el lenguaje en sí. No lo useint.MaxValue
para un límite de velocidad máxima deVehicle
clase o una velocidad máxima aceptable para una aeronave, etc.Evita los valores mágicos como
-1
en tu código. Son engañosos y conducen a errores en el código.Cree su propia clase que sería más sencilla, con los valores mínimos / máximos especificados. Por ejemplo
VehicleSpeed
puede tenerVehicleSpeed.MaxValue
.No siga ninguna directriz anterior y use valores mágicos si es una convención general durante décadas en un campo muy específico, utilizado por la mayoría de las personas que escriben código en este campo.
No olvides mezclar enfoques. Por ejemplo:
¹ Puede crear su propio tipo que incluye infinito. Aquí, solo estoy hablando del
int
tipo nativo .fuente
int
no exprese lo suficiente sobre el tipo para restringir el problema, considere una nueva estructura con más información (instancias constantes de la estructura que representan valores mágicos, por ejemplo, o una enumeración para indicar). O considere la programación por contrato u otras soluciones, pero creo que una estructura personalizada es más sencilla.Nulo no es mejor que un número mágico.
Lo importante es NOMBRAR los valores que tienen efectos mágicos, si tiene que tener esos valores, y asegurarse de que las definiciones de esos nombres estén en algún lugar que pueda ver cualquiera que se encuentre con el valor mágico y wtf.
fuente
MAGIC_NUMBER
El código siempre debe evitarse siempre que sea posible.null
es una expresión de intención mucho más clara.fuente
En C #, muchas clases de CLR tienen un
Empty
miembro estático :System.String.Empty
System.EventArgs.Empty
System.Guid.Empty
System.Drawing.Rectangle.Empty
System.Windows.Size.Empty
Esto evita que tenga que recordar si usar un valor mágico o usar nulo para construir un objeto vacío.
Pero, ¿qué pasa si se trata de un tipo de valor simple como un
int
? En ese caso, considera si estás siendo víctima de la obsesión primitiva . Es muy posible que su propiedad numérica aparentemente simple se beneficie de su propia clase o estructura, lo que le permitiría especificar elEmpty
miembro y también agregar otro comportamiento específico a ese tipo de valor.fuente
En este caso, el valor nulo es una excelente manera de indicar que no hay un máximo. En general, cuando el caso especial significa que el valor en cuestión no se aplica, que simplemente no desea la característica que configura, nulo es una buena indicación de esto.
Un problema con el uso de nulo para representar casos especiales es que solo hay un valor nulo y puede haber múltiples casos especiales. En este caso, pasaría una enumeración como parámetro adicional, que puede indicar un caso especial, o usar el valor int normalmente. (Esto es esencialmente lo que Nullable <> hace por usted, aunque utiliza un booleano en lugar de una enumeración y combina los parámetros en una sola estructura).
fuente
En este caso, creo que un tipo anulable tiene mucho sentido.
Nulo significa ausencia de valor. Este es un concepto claramente diferente a un número que tiene un valor de 0.
Si desea decir "Si no le doy un valor, use el máximo", entonces pasar nulo es la forma exacta correcta de expresar eso.
fuente
Nulo: valor de error común, no especificado, nulo o ausencia de valor.
Cero: un valor real, pero no necesariamente lógico o intuitivo (en este contexto). También un valor común en la inicialización.
En el contexto de su problema, la
timeoutInMilliseconds
propiedad es opcional y no se menciona que la sobrecarga de este enfoque lo descalifique como una opción.Conclusión: hay excepciones y las soluciones varían según el idioma y el dominio; en este caso, elegiría Null. Donde (creo) que algunas personas se equivocan es cuando no separan bien los datos de la interfaz. Solo esperan que cualquier cliente lea la documentación (o implementación) para determinar cómo se utilizarán / manejarán estos valores especiales: los casos especiales se filtran en el programa del cliente y puede ser bastante poco claro. Al agregar una buena capa de abstracción, el uso puede ser mucho más claro.
fuente
Nulo es peor de usar que
MagicNumber
. Null representa la idea expresada mejor, pero no es coherente en todas las plataformas en cómo se comporta, el usoMagicNumber
siempre funciona igual, lo cual es beneficioso.dependiendo del entorno / lenguaje utilizado, nulo podría
MagicNumber
siempre se comporta igual.fuente
Si olvida verificar el número mágico (va a suceder correctamente), entonces un número mágico continuará por un tiempo con datos sin sentido. Mucho mejor tener un valor nulo que cause una excepción lo antes posible.
fuente
Nulo no es la única alternativa a un número mágico.
Nulo es malo. En el ejemplo anterior, es posible que pueda salirse con la suya ya que el código obviamente podría manejar un valor nulo. Pero, en general, lo que sucede cuando comienzas a pasar nulos es que tarde o temprano obtienes una excepción de puntero nulo. Puede que no suceda cuando escribe el código por primera vez, pero el código se mantiene durante mucho más tiempo que solo la primera versión. A menudo es mantenido por personas que no saben tanto sobre el sistema como los desarrolladores originales.
Scala (por ejemplo) tiene una buena alternativa en la clase Opción. La clase Opción tiene uno de dos valores, Algunos, que envuelve el valor que realmente desea y Ninguno, que no tiene ningún valor.
Eso hace obvio para cualquier desarrollador que puede que no haya un valor y que tenga un mejor código para eso. Bueno, debería hacerlo obvio de todos modos.
Y no todos los números mágicos son un problema. Dependiendo del contexto 0, 1, 1024, etc., todo puede ser obvio. 347? Sí, ese que debes evitar. :-)
fuente