Dos casos de estudio sobre los efectos inesperados de NaN en Python y Lua

Fuentes: two case studies of NaN

NaN, el valor especial que representa «no es un número», infringe una de las reglas más asumidas en programación: que todo objeto es igual a sí mismo. Esa peculiaridad, definida en el estándar IEEE-754, se cuela en el diseño de lenguajes que dan por buena esa misma regla y produce comportamientos difíciles de anticipar. Este artículo repasa dos ejemplos concretos en Python y Lua.

En Python, comparar NaN consigo mismo devuelve False, pero la comparación de listas con un único elemento NaN devuelve True. El motivo es una optimización interna: al comparar listas, CPython comprueba primero la identidad de los elementos y solo recurre a la igualdad si las identidades difieren. Como NaN no se compara igual consigo mismo pero sí es el mismo objeto en memoria, la lista [NaN] se considera igual a sí misma. El manual de referencia de Python 3 recoge explícitamente la suposición de que la igualdad debe ser reflexiva, una premisa que NaN viola sin que ello se traduzca en un error.

En Lua, los bucles numéricos for presentan anomalías adicionales. Con la implementación de referencia PUC-Rio, un bucle for i = 0/0, 10 ejecuta su cuerpo una sola vez, y un bucle con inicio y fin iguales a NaN hace lo propio. Cuando NaN actúa como paso, el bucle no se ejecuta si el inicio es menor que el límite, pero sí lo hace una vez cuando el inicio es mayor. La causa está en la implementación: la comprobación inicial usa la expresión limit < init, mientras que las iteraciones siguientes verifican idx <= limit; además, el paso se evalúa con 0 > step, siempre falso para NaN. Ninguno de estos comportamientos está documentado y probablemente responde a un descuido. El artículo señala que bastaría con rechazar NaN en los bucles for numéricos, como ya hace Lua con el paso igual a cero, para evitar que el operador de comparación concreto empleado en la implementación se filtre al comportamiento del intérprete.