En computación (particularmente, en programación ), el valor indefinido es una condición en la que una expresión no tiene un valor correcto , aunque es sintácticamente correcta. Un valor indefinido no debe confundirse con una cadena vacía , un valor booleano "falso" u otros valores "vacíos" (pero definidos). Dependiendo de las circunstancias, la evaluación de un valor indefinido puede conducir a una excepción o comportamiento indefinido , pero en algunos lenguajes de programación pueden ocurrir valores indefinidos durante un curso normal y predecible de ejecución del programa .
Los lenguajes tipados dinámicamente suelen tratar los valores indefinidos de forma explícita cuando es posible. Por ejemplo, Perl tiene el undef
operador [1] que puede "asignar" tal valor a una variable. En otros tipos de sistemas, un valor indefinido puede significar un valor desconocido e impredecible, o simplemente una falla del programa en el intento de su evaluación. Los tipos que aceptan valores NULL ofrecen un enfoque intermedio; ver más abajo .
Manejo
El valor de una función parcial no está definido cuando su argumento está fuera de su dominio de definición . Esto incluye numerosos casos aritméticos como la división por cero , la raíz cuadrada o el logaritmo de un número negativo, etc. Otro ejemplo común es acceder a una matriz con un índice que está fuera de límites, como es el valor en una matriz asociativa para una clave que no contiene. Hay varias formas en que estas situaciones se manejan en la práctica:
Valor reservado
En aplicaciones donde los valores indefinidos deben manejarse con elegancia, es común reservar un valor nulo especial que se distingue de los valores normales. Esto resuelve la dificultad creando un valor definido para representar el caso anteriormente indefinido. Hay muchos ejemplos de esto:
- La biblioteca de E / S estándar de C reserva el valor especial
EOF
para indicar que no hay más entradas disponibles. Lagetchar()
función devuelve el siguiente carácter de entrada disponible, oEOF
si no hay más disponible. (El código de caracteres ASCII define un carácter nulo para este propósito, pero la biblioteca de E / S estándar desea poder enviar y recibir caracteres nulos, por lo que define unEOF
valor separado ). - El estándar aritmético de coma flotante IEEE 754 define un valor especial " no es un número " que se devuelve cuando una operación aritmética no tiene un valor definido. Algunos ejemplos son la división por cero o la raíz cuadrada o el logaritmo de un número negativo .
- El lenguaje de consulta estructurado tiene un
NULL
valor especial para indicar datos faltantes. - El lenguaje Perl permite verificar la definición de una expresión a través del
defined()
predicado. [2] - Muchos lenguajes de programación admiten el concepto de puntero nulo distinto de cualquier puntero válido y, a menudo, se utiliza como retorno de error.
- Algunos lenguajes permiten que la mayoría de los tipos sean anulables, por ejemplo, C # . [3]
- La mayoría de las llamadas al sistema Unix devuelven el valor especial -1 para indicar falla.
Si bien los lenguajes de tipado dinámico a menudo garantizan que las variables no inicializadas tengan un valor nulo de forma predeterminada, los valores de tipado estático a menudo no lo hacen, y distinguen los valores nulos (que están bien definidos) de los valores no inicializados (que no lo están). [3]
Manejo de excepciones
Algunos lenguajes de programación tienen un concepto de manejo de excepciones para lidiar con la falla al devolver un valor. La función regresa de una manera definida, pero no devuelve un valor, por lo que no es necesario inventar un valor especial para devolver.
Una variación de esto es el manejo de señales , que se realiza a nivel del sistema operativo y no está integrado en un lenguaje de programación. Los manejadores de señales pueden intentar algunas formas de recuperación, como terminar parte de un cálculo, pero sin tanta flexibilidad como el manejo de excepciones totalmente integrado.
Funciones de no devolución
Una función que nunca regresa tiene un valor indefinido porque el valor nunca se puede observar. A tales funciones se les asigna formalmente el tipo de fondo , que no tiene valores. Los ejemplos se dividen en dos categorías:
- Funciones que se repiten para siempre . Esto puede surgir deliberadamente o como resultado de una búsqueda de algo que nunca se encontrará. (Por ejemplo, en el caso de un operador μ fallido en una función recursiva parcial ).
- Funciones que terminan el cálculo, como la exitllamada al sistema . Desde dentro del programa, esto es indistinguible del caso anterior, pero hace una diferencia para el invocador del programa.
Comportamiento indefinido
Todos los métodos anteriores de manejo de valores indefinidos requieren que se detecte la indefinición. Es decir, la función llamada determina que no puede devolver un resultado normal y toma alguna acción para notificar a la persona que llama. En el otro extremo del espectro, el comportamiento indefinido coloca la responsabilidad en la persona que llama para evitar llamar a una función con argumentos fuera de su dominio. No hay límite para lo que pueda suceder. En el mejor de los casos, un choque fácilmente detectable ; en el peor de los casos, un error sutil en un cálculo aparentemente no relacionado.
(La definición formal de "comportamiento indefinido" incluye posibilidades aún más extremas, incluidas cosas como " detente y prende fuego " y "haz que los demonios salgan volando de tu nariz". [4] )
El ejemplo clásico es una referencia de puntero colgante . Desreferenciar un puntero válido es muy rápido , pero puede ser muy complejo determinar si un puntero es válido. Por lo tanto, el hardware de la computadora y los lenguajes de bajo nivel como C no intentan validar los punteros antes de desreferenciarlos, sino que pasan la responsabilidad al programador. Esto ofrece velocidad a expensas de la seguridad.
Valor indefinido sensu stricto
La definición estricta de un valor indefinido es una salida superficialmente válida (no nula) que no tiene sentido pero no desencadena un comportamiento indefinido. Por ejemplo, pasar un número negativo a la función de raíz cuadrada inversa rápida producirá un número. No es un número muy útil, pero el cálculo se completará y devolverá algo .
Los valores indefinidos ocurren con especial frecuencia en el hardware. Si un cable no contiene información útil, aún existe y tiene cierto nivel de voltaje. El voltaje no debe ser anormal (por ejemplo, no una sobretensión dañina ), pero el nivel lógico particular no es importante.
La misma situación ocurre en el software cuando se proporciona un búfer de datos pero no se llena por completo. Por ejemplo, la strftime
función de la biblioteca C convierte una marca de tiempo a un formato legible por humanos en un búfer de salida proporcionado. Si el búfer de salida no es lo suficientemente grande para contener el resultado, se devuelve un error y el contenido del búfer no está definido.
En la otra dirección, la openllamada al sistema en POSIX toma tres argumentos: un nombre de archivo, algunas banderas y un modo de archivo. El modo de archivo solo se usa si las banderas incluyen O_CREAT
. es común usar una forma de dos argumentos de open
, que proporciona un valor indefinido para el modo de archivo, cuando O_CREAT
se omite.
A veces es útil trabajar con valores indefinidos de este tipo de forma limitada. El cálculo general aún puede estar bien definido si luego se ignora el valor indefinido.
Como ejemplo de esto, el lenguaje C permite convertir un puntero en un número entero, aunque el valor numérico de ese número entero no está definido. Todavía puede ser útil para depurar, comparar dos punteros para la igualdad o para crear una lista enlazada XOR .
El manejo seguro de valores indefinidos es importante en los sistemas de control de concurrencia optimistas , que detectan las condiciones de carrera después del hecho. Por ejemplo, leer una variable compartida protegida por seqlock producirá un valor indefinido antes de determinar que ocurrió una condición de carrera. Luego, descartará los datos no definidos y volverá a intentar la operación. Esto produce un resultado definido siempre que las operaciones realizadas en los valores indefinidos no produzcan un comportamiento indefinido completo.
Otros ejemplos de valores indefinidos que son útiles son los generadores de números aleatorios y las funciones hash . Los valores específicos devueltos no están definidos, pero tienen propiedades bien definidas y pueden usarse sin error.
Notación
En la teoría de la computabilidad , la indefinición de una expresión se denota como expr ↑ y la definición como expr ↓.
Referencias
- ^ "indef" . Documentación de Perl 5 . 2009-09-25 . Consultado el 26 de marzo de 2010 .
- ^ "definido" . Documentación de Perl 5 . 2009-09-25 . Consultado el 26 de marzo de 2010 .
- ^ a b Carr, Richard (1 de octubre de 2006). "Tipos de datos numéricos que aceptan valores NULL de C #" . Tutorial de fundamentos de C # . Consultado el 27 de marzo de 2010 .
- ^ "Demonios nasales" . Archivo de jerga . Consultado el 12 de junio de 2014 .
Ver también
- Definido e indefinido (matemáticas)
- Nulo (SQL)