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.
Descripción general
En los programas informáticos, las expresiones hacen referencia a variables, tipos de datos, funciones, clases, objetos, bibliotecas, paquetes y otras entidades por su nombre. En este contexto, la resolución de nombres se refiere a la asociación de esos nombres, que no necesariamente son únicos, con las entidades del programa a las que están destinados. Los algoritmos que determinan a qué se refieren 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 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 permiten que un identificador tenga diferentes significados dependiendo de su espacio de nombres asociado;
- ámbitos , que permiten que un identificador tenga diferentes significados en diferentes niveles de ámbito, y que implican varias reglas de anulación y ocultación de ámbitos. En el nivel más básico, la resolución de nombres generalmente intenta encontrar la vinculación en el ámbito contenedor más pequeño, de modo que, por ejemplo, las variables locales reemplazan 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 permite que un identificador tenga diferentes significados dependiendo de cómo se utilice, incluso en un único espacio de nombres o ámbito;
- 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 , y la segunda, resolución de nombres dinámica .
Una idea errónea bastante común es que el tipado dinámico implica resolución de nombres dinámica. Por ejemplo, Erlang es un lenguaje de tipado dinámico, pero tiene resolución de nombres estática. Sin embargo, el tipado estático sí implica resolución de nombres estática.
La resolución estática de nombres detecta, en tiempo de compilación, el uso de variables que no están dentro del ámbito, evitando así errores de programación. Los lenguajes con resolución dinámica de ámbito sacrifican esta seguridad a cambio de mayor flexibilidad; normalmente, pueden establecer y obtener variables dentro del mismo ámbito en tiempo de ejecución.
Por ejemplo, en el REPL interactivo de Python :
>>> número = 99 >>> primer_sustantivo = "problemas" >>> segundo_sustantivo = "perro" >>> # Qué variables usar se deciden en tiempo de ejecución >>> print ( f "Tengo { número } { primer_sustantivo } pero un { segundo_sustantivo } no es uno." ) Tengo 99 problemas pero un perro no es uno.Sin embargo, la comunidad de Python desaconseja depender de la resolución dinámica de nombres en el código. [ 1 ] [ 2 ] Esta característica también podría eliminarse en una versión posterior de Python. [ 3 ]
Ejemplos de lenguajes que utilizan resolución de nombres estática incluyen C , C++ , E , Erlang , Haskell , Java , Pascal , Scheme y Smalltalk . Ejemplos de lenguajes que utilizan resolución de nombres dinámica incluyen algunos dialectos de Lisp , Perl , PHP , Python , Rebol y Tcl .
Enmascaramiento de nombres
El enmascaramiento se produce cuando se utiliza el mismo identificador para diferentes entidades en ámbitos léxicos superpuestos. A nivel de variables (en lugar de nombres), esto se conoce como ocultamiento de variables . Un identificador I' (para la variable X') enmascara a un identificador I (para la variable X) cuando se cumplen dos condiciones.
- Yo tengo el mismo nombre que yo
- 'I' se define en un ámbito que es un subconjunto del ámbito de I.
Se dice que la variable externa X está oculta 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á (y resolverá) primero en el ámbito "más interno", // para sobrescribir correctamente 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). }public int getFoo () { return foo ; }El enmascaramiento de nombres puede causar complicaciones en la sobrecarga de funciones , debido a que la sobrecarga no se produce entre ámbitos en algunos lenguajes, especialmente en C++, lo que requiere que todas las funciones sobrecargadas se redeclaren o se importen explícitamente en un espacio de nombres determinado.
Renombrado alfabético para simplificar la resolución de nombres.
En lenguajes de programación con ámbito léxico que no reflejan los nombres de las variables, la conversión alfa (o cambio de nombre alfa) puede utilizarse para facilitar la resolución de nombres mediante la búsqueda de una sustitución que garantice que ningún nombre de variable oculte otro nombre en un ámbito contenedor. El cambio de nombre alfa puede simplificar el análisis estático del código, ya que solo quien realiza dicho cambio necesita comprender las reglas de ámbito 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 de Point , las variables de instancia x e y están ocultas por variables locales del mismo nombre. Esto podría renombrarse alfanuméricamente a:
clase Punto { privado : doble x , y ;público : Punto ( double a , double b ) { establecerX ( a ); establecerY ( 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 obvio qué usos corresponden a qué declaraciones.
Véase 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. Formato de cadena basado en diccionario" . diveintopython.org . Mark Pilgrim . Consultado el 23 de enero de 2011 .
- ↑ "9. Clases - Documentación de Python" . Consultado el 24/07/2019 .
Es importante tener en cuenta que los ámbitos se determinan textualmente: el ámbito global de una función definida en un módulo es el espacio de nombres de ese módulo, independientemente de dónde o con 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 estática de nombres, en tiempo de compilación, ¡así que no confíe en la resolución dinámica de nombres! (De hecho, las variables locales ya se determinan estáticamente).
- Bibliotecas informáticas
- Construcción de compiladores