2.2 Nombres, Ligado y Ámbito Ligado estático y dinámico, reglas de ámbito y prueba de tipos.
Nombres l
Identificador que designa en el lenguaje un elemento u objeto de programa l
l
l l l
l l l l
l
l l
El mismo nombre puede ser usado para referirse a diferentes objetos (direcciones), según el ámbito. Diferentes nombres pueden referirse a un mismo objeto (alias), lo que puede provocar efectos laterales.
Ejemplo: l l
Union y punteros en C y C++ Variables dinámicas en PERL
Abstracción de un objeto de memoria, que tiene los siguientes atributos: l l l
Largo (con significativo) del nombre Tipos de caracteres aceptados (e.g. conector _) Sensibilidad a mayúsculas y minúsculas Palabras reservadas
Un nombre puede ser asociado con diferentes direcciones en diferentes partes y tiempo de ejecución de un programa
Nombres e Identificadores Variables Tipos Ámbito Constantes
Variables
(e.g. variable, tipo, constante, función, etc.)
Dirección de una Variable
l
l
Aspectos de diseño: l
l
Conceptos
l l l
Nombre (identificador) Dirección (l-value: ¿Dónde está localizada?) Valor (r-value: contenido) Tipo (tipo de dato que almacena y operaciones válidas) Tiempo de vida (¿Cuándo se crea y se destruye?) Ámbito (¿Dónde se puede referenciar?)
Ligado (Binding) l
Definición: Proceso de asociación de un atributo a una entidad del lenguaje. l l
l
Variable:Dirección, tipo → Nombre Operador: Código → Símbolo
El tiempo de ligado se refiere al instante en que sucede la asociación: l
l
Estática: diseño o implementación del lenguaje; compilación, enlace o carga del programa Dinámica: ejecución del programa
1
a) Ligado de Tipos a Variables
b) Ligado a Memoria y Tiempo de Vida de Variables
l
Variables deben ser ligadas a un tipo antes de usarlas.
l
l
Ligado Estático : con declaración explícita o implícita l Lenguajes modernos usan sólo declaración explícita l C y C++ hacen la diferencia entre declaración y definición Ligado Dinámico : en el momento de la asignación l Ventaja: Permite programar en forma genérica l Desventaja: disminuye capacidad de detección de errores y aumento del costo (ejecución)
l
l
l
El carácter de un lenguaje está en gran medida determinado por cómo se administra la memoria . A la variables se les puede asignar y liberar memoria de un espacio común (liberación implícita requiere de un recolector de basura). Las variables escalares, según tipo de ligado, se clasifican en: l l l
b.1) Variables Estáticas l l
l
l
l
l l
Útil para variables globales Para variables sensibles a la historia de un subprograma (e.g. uso de static en variables de funciones C y C++) Acceso directo permite mayor eficiencia
La memoria se asigna y libera en forma explícita por el programador, usando un operador del lenguaje o una llamada al sistema l l
l
l
l l
l
Falta de flexibilidad No soportan recursión Impide compartir memoria entre diferentes variables
b.3) Variables Dinámicas de Heap (explícita)
l
l
Desventajas l
l
b.2) Variables Dinámicas de Stack
Ligadas antes de la ejecución Ventajas l
C++ dispone del operador new y delete C usa llamada al sistema malloc() y free() Java no permite la liberación explícita
Ventaja: útil para estructuras dinámicas usando punteros. Desventaja: Dificultad en su uso correcto
Estáticas Dinámica de stack Dinámica de heap (explícita o implícita)
Ligadas (a la memoria) en el momento en que la ejecución alcanza el código asociado a la declaración. Típicamente el tipo se liga estáticamente. En Pascal se asigna memoria en el momento de ingresar al bloque que define el ámbito de la variable. En C y C++ las variables son por defecto de este tipo (denominadas variables automáticas).
b.4) Variables Dinámicas de Heap (implícita) l
l
Se ligan al heap sólo cada vez que ocurre una asignación Ventajas: l
l
l
Alto grado de flexibilidad (un nombre sirve para cualquier cosa) Permite escribir código genérico
Desventaja : l l
Alto costo de ejecución Pérdida en la capacidad de detección de errores
2
Tipo de Datos l
l
l l
Verificación de Tipo l
Para generalizar, supongamos: l La asignación es un operador binario con una variable y una expresión como operandos l Un subprograma es un operador cuyos parámetros son sus operandos Verificación de tipo es asegurar que los operandos de un operador son de tipo compatible. Un tipo compatible es uno legal o que mediante reglas el compilador lo puede convertir a legal. La conversión automática de tipo se denomina coerción
Si todos los tipos se ligan estáticamente
⇒ verificaci ón de tipos se puede hacer estáticamente. l
l
l
Ligado dinámico requiere realizar una verificación de tipo en tiempo de ejecución. Lenguajes modernos prefieren una verificación de tipo estática Verificación de tipo se complica cuando se permite almacenar valores de diferente tipo en una variable => (e.g. Registro con variante en Pascal y Union en C).
Tipificado Fuerte (strong typing) l
Un lenguaje es de tipificado fuerte si permite detectar siempre los errores de tipo: l l
l
Cada nombre debe ser ligado estáticamente a un tipo Ligado dinámico a memoria requiere verificación en tiempo de ejecución
Compatibilidad de Tipos l
l
l
l
Ejemplos: l l l
¡Pascal casi lo es! (registro con variante es excepción) C y C++ no lo son (parámetros en funciones y union) Java si lo es (permite forzar conversión de tipo)
Ejemplo: Pascal TYPE mes_t = 1..12; VAR indice : mes_t; contador: integer; {otro ejemplo} TYPE celsius = real; fahrenheit = real;
Compatibilidad de nombre
Compatibilidad de estructura l l
l
Las variables están en la misma declaración o usan el mismo nombre de tipo Fácil implementación, pero muy restrictivo Si los tipos tienen la misma estructura Más flexible, pero de difícil implementación
Algunos lenguajes permiten forma intermedia! (e.g. Equivalencia declarativa en Pascal)
Ejemplo: C y C++ struct s1 {int c1; real c2 }; struct s2 {int c1; real c2 }; s1 s2
x; y = x;
/* error de compatibilidad */
{otro ejemplo}
typedef char* pchar; pchar p1, p2;
TYPE tipo1 = ARRAY [1 ..10] OF integer; tipo2 = ARRAY [1 ..10] OF integer; {tipo1 tipo2} tipo3 = tipo2; {equivalencia declarativa}
char* p3 = p1;
3
Ámbito (Scope) l
l
l
a) Ámbito Estático
Rango de sentencias en el cual un nombre es visible. Nombres pueden ser sólo referenciadas dentro del ámbito. Nombres no locales son los que son visibles dentro de un bloque, pero han sido declarado fuera de él.
Ejemplo: Pascal
procedure p2; var x: integer; begin { p2} … x … end; {p2}
p1
void f1 (…) { int i,m; … }
main p2
b) Ámbito Dinámico
l
l
Ámbito de nombres no locales está definido por secuencia de llamadas a subprogramas. Anidamiento de llamadas define ascendencia dinámica Problemas: l l l
l
extern i n t i ; int j = 100; static i n t k ;
begin {main} … end . {main}
l
l
Ámbito estático: puede ser determinado antes de la ejecución Usado en la mayoría de los lenguajes imperativos . Es normal permitir el anidamiento en una jerarquía de ámbitos (excepto: C, C++ y Java), que define una ascendencia estática
Ejemplo: C
program main; var x: integer; procedure p1; begin { p1} … x … end; {p1}
l
No permite proteger variables locales No se pueden verificar estáticamente los tipos Programas son difíciles de leer y más lentos
void f2 (…) { int static k=0; if (!k) { printf(“primera vez\n”); k=1}; for (int j=0; j++; j
2.2 Nombres, Ligado y Ámbito Ligado estático y dinámico, reglas de ámbito y prueba de tipos.
Nombres l
Identificador que designa en el lenguaje un elemento u objeto de programa l
l
l l l
l l l l
l
l l
El mismo nombre puede ser usado para referirse a diferentes objetos (direcciones), según el ámbito. Diferentes nombres pueden referirse a un mismo objeto (alias), lo que puede provocar efectos laterales.
Ejemplo: l l
Union y punteros en C y C++ Variables dinámicas en PERL
Abstracción de un objeto de memoria, que tiene los siguientes atributos: l l l
Largo (con significativo) del nombre Tipos de caracteres aceptados (e.g. conector _) Sensibilidad a mayúsculas y minúsculas Palabras reservadas
Un nombre puede ser asociado con diferentes direcciones en diferentes partes y tiempo de ejecución de un programa
Nombres e Identificadores Variables Tipos Ámbito Constantes
Variables
(e.g. variable, tipo, constante, función, etc.)
Dirección de una Variable
l
l
Aspectos de diseño: l
l
Conceptos
l l l
Nombre (identificador) Dirección (l-value: ¿Dónde está localizada?) Valor (r-value: contenido) Tipo (tipo de dato que almacena y operaciones válidas) Tiempo de vida (¿Cuándo se crea y se destruye?) Ámbito (¿Dónde se puede referenciar?)
Ligado (Binding) l
Definición: Proceso de asociación de un atributo a una entidad del lenguaje. l l
l
Variable:Dirección, tipo → Nombre Operador: Código → Símbolo
El tiempo de ligado se refiere al instante en que sucede la asociación: l
l
Estática: diseño o implementación del lenguaje; compilación, enlace o carga del programa Dinámica: ejecución del programa
1
a) Ligado de Tipos a Variables
b) Ligado a Memoria y Tiempo de Vida de Variables
l
Variables deben ser ligadas a un tipo antes de usarlas.
l
l
Ligado Estático : con declaración explícita o implícita l Lenguajes modernos usan sólo declaración explícita l C y C++ hacen la diferencia entre declaración y definición Ligado Dinámico : en el momento de la asignación l Ventaja: Permite programar en forma genérica l Desventaja: disminuye capacidad de detección de errores y aumento del costo (ejecución)
l
l
l
El carácter de un lenguaje está en gran medida determinado por cómo se administra la memoria . A la variables se les puede asignar y liberar memoria de un espacio común (liberación implícita requiere de un recolector de basura). Las variables escalares, según tipo de ligado, se clasifican en: l l l
b.1) Variables Estáticas l l
l
l
l
l l
Útil para variables globales Para variables sensibles a la historia de un subprograma (e.g. uso de static en variables de funciones C y C++) Acceso directo permite mayor eficiencia
La memoria se asigna y libera en forma explícita por el programador, usando un operador del lenguaje o una llamada al sistema l l
l
l
l l
l
Falta de flexibilidad No soportan recursión Impide compartir memoria entre diferentes variables
b.3) Variables Dinámicas de Heap (explícita)
l
l
Desventajas l
l
b.2) Variables Dinámicas de Stack
Ligadas antes de la ejecución Ventajas l
C++ dispone del operador new y delete C usa llamada al sistema malloc() y free() Java no permite la liberación explícita
Ventaja: útil para estructuras dinámicas usando punteros. Desventaja: Dificultad en su uso correcto
Estáticas Dinámica de stack Dinámica de heap (explícita o implícita)
Ligadas (a la memoria) en el momento en que la ejecución alcanza el código asociado a la declaración. Típicamente el tipo se liga estáticamente. En Pascal se asigna memoria en el momento de ingresar al bloque que define el ámbito de la variable. En C y C++ las variables son por defecto de este tipo (denominadas variables automáticas).
b.4) Variables Dinámicas de Heap (implícita) l
l
Se ligan al heap sólo cada vez que ocurre una asignación Ventajas: l
l
l
Alto grado de flexibilidad (un nombre sirve para cualquier cosa) Permite escribir código genérico
Desventaja : l l
Alto costo de ejecución Pérdida en la capacidad de detección de errores
2
Tipo de Datos l
l
l l
Verificación de Tipo l
Para generalizar, supongamos: l La asignación es un operador binario con una variable y una expresión como operandos l Un subprograma es un operador cuyos parámetros son sus operandos Verificación de tipo es asegurar que los operandos de un operador son de tipo compatible. Un tipo compatible es uno legal o que mediante reglas el compilador lo puede convertir a legal. La conversión automática de tipo se denomina coerción
Si todos los tipos se ligan estáticamente
⇒ verificaci ón de tipos se puede hacer estáticamente. l
l
l
Ligado dinámico requiere realizar una verificación de tipo en tiempo de ejecución. Lenguajes modernos prefieren una verificación de tipo estática Verificación de tipo se complica cuando se permite almacenar valores de diferente tipo en una variable => (e.g. Registro con variante en Pascal y Union en C).
Tipificado Fuerte (strong typing) l
Un lenguaje es de tipificado fuerte si permite detectar siempre los errores de tipo: l l
l
Cada nombre debe ser ligado estáticamente a un tipo Ligado dinámico a memoria requiere verificación en tiempo de ejecución
Compatibilidad de Tipos l
l
l
l
Ejemplos: l l l
¡Pascal casi lo es! (registro con variante es excepción) C y C++ no lo son (parámetros en funciones y union) Java si lo es (permite forzar conversión de tipo)
Ejemplo: Pascal TYPE mes_t = 1..12; VAR indice : mes_t; contador: integer; {otro ejemplo} TYPE celsius = real; fahrenheit = real;
Compatibilidad de nombre
Compatibilidad de estructura l l
l
Las variables están en la misma declaración o usan el mismo nombre de tipo Fácil implementación, pero muy restrictivo Si los tipos tienen la misma estructura Más flexible, pero de difícil implementación
Algunos lenguajes permiten forma intermedia! (e.g. Equivalencia declarativa en Pascal)
Ejemplo: C y C++ struct s1 {int c1; real c2 }; struct s2 {int c1; real c2 }; s1 s2
x; y = x;
/* error de compatibilidad */
{otro ejemplo}
typedef char* pchar; pchar p1, p2;
TYPE tipo1 = ARRAY [1 ..10] OF integer; tipo2 = ARRAY [1 ..10] OF integer; {tipo1 tipo2} tipo3 = tipo2; {equivalencia declarativa}
char* p3 = p1;
3
Ámbito (Scope) l
l
l
a) Ámbito Estático
Rango de sentencias en el cual un nombre es visible. Nombres pueden ser sólo referenciadas dentro del ámbito. Nombres no locales son los que son visibles dentro de un bloque, pero han sido declarado fuera de él.
Ejemplo: Pascal
procedure p2; var x: integer; begin { p2} … x … end; {p2}
p1
void f1 (…) { int i,m; … }
main p2
b) Ámbito Dinámico
l
l
Ámbito de nombres no locales está definido por secuencia de llamadas a subprogramas. Anidamiento de llamadas define ascendencia dinámica Problemas: l l l
l
extern i n t i ; int j = 100; static i n t k ;
begin {main} … end . {main}
l
l
Ámbito estático: puede ser determinado antes de la ejecución Usado en la mayoría de los lenguajes imperativos . Es normal permitir el anidamiento en una jerarquía de ámbitos (excepto: C, C++ y Java), que define una ascendencia estática
Ejemplo: C
program main; var x: integer; procedure p1; begin { p1} … x … end; {p1}
l
No permite proteger variables locales No se pueden verificar estáticamente los tipos Programas son difíciles de leer y más lentos
void f2 (…) { int static k=0; if (!k) { printf(“primera vez\n”); k=1}; for (int j=0; j++; j