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 previstos del programa.
Descripción general
Las expresiones en los programas de computadora hacen referencia a variables, tipos de datos, funciones, clases, objetos, bibliotecas, paquetes y otras entidades por nombre. En ese contexto, la resolución de nombres se refiere a la asociación de esos nombres no necesariamente únicos con las entidades de programa previstas. Los algoritmos que determinan a qué se refieren esos identificadores en contextos específicos son 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 solo una simple búsqueda en una tabla , mientras que la resolución de nombres en C ++ es extremadamente complicada ya que implica:
- espacios de nombres , que hacen posible que un identificador tenga diferentes significados dependiendo de su espacio de nombres asociado;
- alcances , que hacen posible que un identificador tenga diferentes significados en diferentes niveles de alcance, y que implica varias reglas de anulación y ocultación de alcance. En el nivel más básico, la resolución de nombres generalmente intenta encontrar el enlace en el ámbito más pequeño, de modo que, por ejemplo, las variables locales reemplacen a las variables globales; esto se llama sombreado .
- reglas de visibilidad , que determinan si los identificadores de espacios de nombres o ámbitos específicos son visibles desde el contexto actual;
- sobrecarga , que hace posible que un identificador tenga diferentes significados dependiendo de cómo se use, incluso en un solo espacio de nombres o alcance;
- accesibilidad , que determina si los identificadores de un ámbito que de otro modo sería visible son realmente accesibles y participan en el proceso de resolución de nombres.
Estático versus dinámico
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 , la última se denomina resolución de nombres dinámica .
Un error algo común es que la escritura dinámica implica una resolución dinámica de nombres. Por ejemplo, Erlang se escribe dinámicamente pero tiene una resolución de nombres estática. Sin embargo, la escritura estática implica una resolución de nombres estática.
La resolución de nombres estáticos detecta, en tiempo de compilación, el uso de variables que no están dentro del alcance; Previniendo errores del programador. Los idiomas con resolución dinámica de osciloscopio sacrifican esta seguridad en aras de una mayor flexibilidad; normalmente pueden establecer y obtener variables en el mismo ámbito en tiempo de ejecución.
Por ejemplo, en el REPL interactivo de Python :
>>> número = 99 >>> primer_anuncio = "problemas" >>> segundo_anuncio = "sabueso" >>> # Qué variables usar se deciden en tiempo de ejecución >>> print ( f " Obtuve { número } { primer_anuncio } pero un { second_noun } no es uno. " ) Tengo 99 problemas, pero un sabueso no es uno.
Sin embargo, la comunidad de Python desaconseja confiar en la resolución dinámica de nombres en el código. [1] [2] La función también puede eliminarse en una versión posterior de Python. [3]
Los ejemplos de lenguajes que utilizan la resolución de nombres estática incluyen C , C ++ , E , Erlang , Haskell , Java , Pascal , Scheme y Smalltalk . Los ejemplos de lenguajes que utilizan la resolución dinámica de nombres incluyen algunos dialectos Lisp , Perl , PHP , Python , REBOL y Tcl .
Enmascaramiento de nombre
El enmascaramiento ocurre cuando se usa el mismo identificador para diferentes 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
- Tengo el mismo nombre que yo
- I 'se define en un alcance que es un subconjunto del alcance de I
Se dice que la variable externa X está sombreada por la variable interna X '.
Por ejemplo, el parámetro "foo" sombrea la variable local "foo" en este patrón común:
privado int foo ; // El nombre "foo" se declara en el ámbito externopublic void setFoo ( int foo ) { // El nombre "foo" se declara en el ámbito interno y es de función local. esto . foo = foo ; // Dado que "foo" se encontrará (y resolverá) primero en el alcance '' 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 función). }public int getFoo () { return 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, en particular C ++, lo que requiere que todas las funciones sobrecargadas se vuelvan a declarar o se importen explícitamente a un espacio de nombres determinado.
Cambio de nombre alfa para hacer que la resolución de nombres sea trivial
En los lenguajes de programación con ámbito léxico que no se refleja en los nombres de las variables, se puede utilizar la conversión α (o el cambio de nombre α) para facilitar la resolución de nombres al encontrar una sustitución que asegure que ningún nombre de variable enmascare otro nombre en un ámbito contenedor. El cambio de nombre alfa puede facilitar el análisis de código estático, ya que solo el cambiador de nombre alfa necesita comprender las reglas de alcance del lenguaje.
Por ejemplo, en este código:
class Point { privado : doble x , y ;public : Point ( doble x , doble y ) { // xey declarados aquí enmascaran los privados setX ( x ); setY ( y ); } void setX ( doble newx ) { x = newx ; } void setY ( doble newy ) { y = newy ; } }
dentro del constructor Point , las variables de clasex y y están sombreados por variables locales del mismo nombre. Esto podría cambiarse de nombre alfa a:
class Point { privado : doble x , y ;público : Punto ( doble a , doble b ) { setX ( a ); setY ( b ); } void setX ( doble newx ) { x = newx ; } void setY ( doble newy ) { y = newy ; } }
En la nueva versión, no hay enmascaramiento, por lo que es inmediatamente obvio qué usos corresponden a qué declaraciones.
Ver también
Referencias
- ^ "[Python-Ideas] función de utilidad str.format" . 9 de mayo de 2009 . Consultado el 23 de enero de 2011 .
- ^ "8.6. Formateo de cadenas basado en diccionario" . diveintopython.org . Mark Pilgrim . Consultado el 23 de enero de 2011 .
- ^ "9. Clases - Documentación de Python" . Consultado el 24 de julio de 2019 .
Es importante darse cuenta de 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 por qué alias se llame a la función. Por otro lado, la búsqueda real de nombres se realiza dinámicamente, 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 dinámica de nombres! (De hecho, las variables locales ya están determinadas estáticamente).