En los lenguajes de programación , la resolución de nombres es la resolución de los tokens dentro de las expresiones del programa a los componentes del programa previstos.
Las expresiones de los programas informáticos hacen referencia a variables, tipos de datos, funciones, clases, objetos, bibliotecas, paquetes y otras entidades por su nombre. En ese contexto, la resolución de nombres se refiere a la asociación de esos nombres no necesariamente únicos con las entidades del programa previstas. Los algoritmos que determinan a qué hacen referencia esos identificadores en contextos específicos forman parte de la definición del lenguaje.
La complejidad de estos algoritmos está influenciada por la sofisticación del lenguaje. Por ejemplo, la resolución de nombres en lenguaje ensamblador generalmente implica una única búsqueda simple en una tabla , mientras que la resolución de nombres en C++ es extremadamente complicada, ya que implica:
En los lenguajes de programación , la resolución de nombres se puede realizar en tiempo de compilación o en tiempo de ejecución . La primera se denomina resolución de nombres estática y la segunda se denomina resolución de nombres dinámica .
Un error bastante común es pensar que la tipificación dinámica implica una resolución de nombres dinámica. Por ejemplo, Erlang tiene tipado dinámico pero resolución de nombres estática. Sin embargo, la tipificación estática implica una resolución de nombres estática.
La resolución de nombres estática detecta, en tiempo de compilación, el uso de variables que no están dentro del ámbito, lo que evita errores de programación. Los lenguajes con resolución de ámbito dinámica sacrifican esta seguridad a cambio de más flexibilidad; normalmente pueden establecer y obtener variables en el mismo ámbito en tiempo de ejecución.
Por ejemplo, en el REPL interactivo de Python :
>>> numero = 99 >>> primer_nombre = "problemas" >>> segundo_nombre = "perro" >>> # Las variables que se utilizarán se deciden en tiempo de ejecución >>> print ( f "Tengo { numero } { primer_nombre } pero un { segundo_nombre } no es uno." ) Tengo 99 problemas pero un perro no es uno.
Sin embargo, la comunidad Python no recomienda confiar en la resolución dinámica de nombres en el código. [1] [2] La característica también puede eliminarse en una versión posterior de Python. [3]
Entre los ejemplos de lenguajes que utilizan la resolución de nombres estática se incluyen C , C++ , E , Erlang , Haskell , Java , Pascal , Scheme y Smalltalk . Entre los ejemplos de lenguajes que utilizan la resolución de nombres dinámica se incluyen algunos dialectos de Lisp , Perl , PHP , Python , Rebol y Tcl .
El enmascaramiento se produce cuando se utiliza el mismo identificador para distintas entidades en ámbitos léxicos superpuestos. A nivel de variables (en lugar de nombres), esto se conoce como sombreado de variables . Un identificador I' (para la variable X') enmascara un identificador I (para la variable X) cuando se cumplen dos condiciones
Se dice que la variable externa X está ensombrecida por la variable interna X'.
Por ejemplo, el parámetro "foo" oculta la variable local "foo" en este patrón común:
private int foo ; // El nombre "foo" se declara en el ámbito externo public void setFoo ( int foo ) { // El nombre "foo" se declara en el ámbito interno y es local a la función. this.foo = foo ; // Dado que "foo" se encontrará primero (y se resolverá) en el ámbito ''más interno'', // para sobrescribir con éxito el valor almacenado del atributo "foo" // con el nuevo valor del parámetro entrante "foo", se hace una distinción // entre "this.foo" (el atributo del objeto) y "foo" (el parámetro de la función). } público int getFoo () { devolver foo ; }
El enmascaramiento de nombres puede causar complicaciones en la sobrecarga de funciones , debido a que la sobrecarga no ocurre en todos los ámbitos en algunos lenguajes, especialmente C++, lo que requiere que todas las funciones sobrecargadas se vuelvan a declarar o se importen explícitamente en un espacio de nombres determinado.
En lenguajes de programación con alcance léxico que no se reflejan en los nombres de las variables, se puede utilizar la conversión alfa (o cambio de nombre alfa) para facilitar la resolución de nombres al encontrar una sustitución que garantice que ningún nombre de variable enmascare otro nombre en un ámbito que lo contenga. El cambio de nombre alfa puede facilitar el análisis de código estático , ya que solo el renombrador alfa necesita comprender las reglas de alcance del lenguaje.
Por ejemplo, en este código:
clase Punto { privado : doble x , y ; public : Point ( double x , double y ) { // x e y declarados aquí enmascaran los privados setX ( x ); setY ( y ); } void setX ( double newx ) { x = newx ; } void setY ( double newy ) { y = newy ; } }
Dentro del constructor Point , las variables de instancia x e y están sombreadas por variables locales del mismo nombre. Esto podría cambiarse de nombre alfa a:
clase Punto { privado : doble x , y ; público : Punto ( doble a , doble b ) { setX ( a ); setY ( b ); } void setX ( double newx ) { x = newx ; } void setY ( double newy ) { y = newy ; } }
En la nueva versión no hay enmascaramiento, por lo que resulta inmediatamente evidente qué usos corresponden a qué declaraciones.
Es importante tener en cuenta que los alcances se determinan textualmente: el alcance global de una función definida en un módulo es el espacio de nombres de ese módulo, sin importar desde dónde o con qué alias se llama a la función. Por otro lado, la búsqueda real de nombres se realiza de forma dinámica, en tiempo de ejecución; sin embargo, la definición del lenguaje está evolucionando hacia la resolución de nombres estática, en tiempo de "compilación", así que no confíe en la resolución de nombres dinámica. (De hecho, las variables locales ya se determinan estáticamente).