Variables, ámbito y comprobación de tipos

Get Started. It's Free
or sign up with your email address
Variables, ámbito y comprobación de tipos by Mind Map: Variables, ámbito y comprobación de tipos

1. 4. Ámbito

1.1. Ámbito de una variable de programa: rango de sentencias en las que es visible la variable - Una variable es visible en una sentencia si puede referenciarse en dicha sentencia - Las reglas de ámbito de un lenguaje determinan cómo se asocian las referencias a variables declaradas fuera del subprograma o bloque que se está ejecutando con sus declaraciones ⇒ con sus atributos - Una variable es local en una unidad de programa o bloque si está declarada en él. Las variables no locales de una unidad de programa o bloque son aquellas visibles en dicha unidad o bloque pero no declaradas en él

1.1.1. 4.1 Ámbito estático

1.1.1.1. Ámbito estático (introducido por ALGOL 60): método de ligadura de nombres a variables no locales que ocurre en tiempo de compilación ♦ En la mayoría de lenguajes con ámbito estático (C es una de las excepciones) pueden anidarse los subprogramas → cada subprograma crea su propio ámbito ⇒ el resultado es una jerarquía de ámbitos

1.1.1.2. ¿Cómo se determinan los atributos de una variable en un lenguaje con ámbito estático? 1º. Se busca su declaración local, y si no se encuentra 2º. Se continúa la búsqueda en el bloque que lo declara, su padre estático. Si no se encuentra, 3º. Se continúa la búsqueda en la unidad que declara a esta última. Así hasta que se encuentra la declaración de la variable o se alcance la unidad de declaración mayor ⇒ error: utilización de una variable no declarada

1.1.1.3. El padre estático de un subprograma y los padres estáticos de éste hasta el programa principal se denominan antepasados estáticos

1.1.1.4. En lenguajes con ámbito estático, una declaración de una variable oculta cualquier declaración de otra variable con el mismo nombre en un ámbito que englobe al que incluye dicha declaración 

1.1.1.4.1. La referencia a la variable x en sub2 se corresponde con la declaración en sub2 ⇒ se oculta la declaración de x en mayor

1.1.1.4.2. Hay lenguajes que permiten hacer referencia a variables ocultas declaradas en antepasados estáticos  Ej: Ada. Sintaxis: nombre_unidad_de_programa.nombre_variable mayor.x

1.1.1.5. Algunos lenguajes (herederos de ALGOL 60) permiten definir nuevos ámbitos estáticos en mitad de código ejecutable ⇒ son variables locales a esa sección de código. Son variables dinámicas de pila ⇒ se les asigna espacio al comenzar la sección y se desasigna cuando se sale de ella

1.1.1.6. Las secciones de código en la que pueden definirse variables locales se denominan bloques

1.1.1.6.1. - Los bloques son el origen de la expresión lenguajes estructurados en bloques - Aunque a Pascal se le considera un lenguaje estructurado en bloques no dispone de bloques no procedurales - En C, cualquier grupo de sentencia compuesta (secuencia de sentencias englobadas entre llaves) puede definir un nuevo ámbito. - Java permite que la definición de una variable aparezca en cualquier lugar de una función → el ámbito de la variable comienza en la sentencia de definición y acaba en el final del bloque que la incluye - Los ámbitos definidos por bloques se tratan igual que los creados por subprogramas 

1.1.2. 4.2 Ámbito dinámico

1.1.2.1. Ámbito dinámico (APL, SNOBOL4): basado en la secuencia de llamadas a subprogramas y no en la relación sintáctica entre ellos ⇒ el ámbito sólo puede determinarse en tiempo de ejecución

1.1.2.2. ¿Cómo se determinan los atributos de una variable en un lenguaje con ámbito dinámico? En tiempo de ejecución:

1.1.2.2.1. 1º. Se busca su declaración local, y si no se encuentra 2º. Se continúa la búsqueda en su padre dinámico, el subprograma que realizó la llamada. Si no se encuentra 3º. Se continúa la búsqueda en los antepasados dinámicos. Así hasta que se encuentra la declaración de la variable. Si no se encuentra la declaración en ningún antecesor dinámico ⇒ error en tiempo de ejecución

1.1.3. 4.3 Entorno de referencia

1.1.3.1. Entorno de referencia de una sentencia: colección de todos los identificadores visibles en dicha sentencia

1.1.3.1.1. - Lenguajes con ámbito estático: el entorno de referencia de una sentencia está compuesto por las variables declaradas en su ámbito local más todas las variables visibles de sus antepasados estáticos - Lenguajes con ámbito dinámico: el entorno de referencia de una sentencia está compuesto por las variables declaradas localmente más todas las variables visibles del resto de subprogramas activos

2. 5. Constantes

2.1. Constante: objeto al que se le liga un valor sólo en el momento en el que se le liga el espacio ⇒ su valor no puede cambiarse por asignación o por sentencia de entrada

2.2. Ventajas: - Aumenta la fiabilidad y legibilidad de los programas - El valor aparece en una sola línea de programa ⇒ más fácil su modificación

2.3. Constantes manifiestas: constantes con ligadura estática de valores - Pascal: la declaración de una constante requiere un valor simple - Modula-2: permite expresiones constantes (constantes ya declaradas, literales y operadores)

2.4. Otros lenguajes (Ada, Java) permiten ligadura dinámica de valores a constantes ⇒ pueden aparecer variables

3. 6. Inicialización de variables

3.1. Otros lenguajes (Ada, Java) permiten ligadura dinámica de valores a constantes ⇒ pueden aparecer variables

3.2. Variables estáticas: inicialización sucede una sola vez antes del momento de la ejecución

3.3. Variables con ligadura dinámica de espacio: la inicialización también es dinámica

3.4. Inicialización en algunos lenguajes:

3.4.1. Pascal: No tiene sentencias de inicialización

3.4.2. C: en la sentencia de declaración puede indicarse un valor inicial Ej.: int i = 10;

3.4.3. Ada: la inicialización puede incluir nombres de otras constantes o variables visibles en el momento de la elaboración de la inicialización Ej.: contador: integer := num_elem + 1; num_elem puede ser el nombre de una variable o constante

3.5. Variables no inicializadas

3.5.1. Las declaraciones sin inicialización crean variables no inicializadas: se les liga memoria pero su contenido es arbitrario y no puede ser interpretado como un valor del tipo del objeto declarado. El uso de un valor no inicializado produce resultados impredecibles y debe evitarse

3.5.2. Posibles aproximaciones que pueden utilizar los LP:

3.5.2.1. Se ignora el problema y se considera responsabilidad del programador no emplear valores no inicializados. Poco elegante

3.5.2.2. Todas las declaraciones inicializan el espacio asignado a un valor apropiado, definido para cada tipo básico. Por ej., punteros a null y valores numéricos a cero. Puede llevar a errores

3.5.2.3. No existen declaraciones sin inicialización ⇒ el programador debe proporcionar un valor de inicialización adecuado para cada elemento declarado

3.5.2.4. Existe un valor especial para cada tipo denominado omega, que representa la propiedad de ausencia de inicialización. Este valor se propaga en las expresiones (omega + 3 → omega). Permite al programador comprobar dinámicamente si una variable está o no inicializada

4. 1. Variables

4.1. 1.1 Nombre

4.1.1. Cadena de caracteres empleada para reconocer alguna entidad del programa. - Conectores - Palabras especiales, claves, reservadas y nombres predefinidos

4.2. 1.2 Dirección

4.2.1. Dirección de una variable en memoria.

4.3. 1.3 Tipo

4.3.1. Determina el rango de valores qe puede tomar una variable y el conjunto de operaciones

4.4. 1.4 Valor

4.4.1. Contenido de la celda o celdas de memoria asociadas a las variables

5. 2. Ligadura - Ligadura estática: si ocurre antes del tiempo de ejecución y permanece inalterable durante la ejecución del programa. - Ligadura dinámica: si ocurre durante del tiempo de ejecución o puede cambiar en el transcurso de la ejecución del programa.

5.1. 2.1 Ligadura de Tipos - Antes de que una variable pueda ser referenciada en un programa debe haber sido ligada a un tipo de dato. Aspectos importantes: cuándo se liga el tipo y cómo se especifica

5.1.1. A. Ligadura estática de tipos

5.1.1.1. Declaración Implícita - Forma de asociar variables con tipos a través de convenciones sintácticas. La primera aparición del identificador constituye su declaración implícita

5.1.1.2. Declaración Explícita - Se utiliza una sentencia que declara una lista de identificadores como de un tipo determinado

5.1.1.3. Algoritmo de inferencia de tipos - Determina los tipos de las variables que intervienen en las expresiones sin que sean declaradas de forma explícita por el programador o da un mensaje de error si no puede inferirse

5.1.2. B. Ligadura dinámica de tipos

5.1.2.1. Ventaja: proporciona muchísima flexibilidad de programación

5.1.2.2. Desventajas: No se detectan incorrecciones de tipo en las asignaciones. El tipo de la parte izquierda simplemente se cambia al de la derecha

5.2. 2.2 Ligadura de espacio y tiempo de vida - Proceso de asignación: ligar celdas de memoria, tomadas de zonas de memoria disponible, a variables - Proceso de desasignación: desligar las celdas de memoria de la variable y devolver las celdas a las zonas de memoria disponible - Tiempo de vida de una variable de programa: tiempo durante el cual la variable está ligada a una localización específica de memoria tiempo entre asignación y desasignación de espacio

5.2.1. A. Variables estáticas

5.2.1.1. - Se ligan a celdas de memoria antes de que comience la ejecución del programa y permanece ligada a las mismas celdas hasta que acaba la ejecución del programa - Las variables globales son variables estáticas - Puede ser conveniente declarar variables en subprogramas que retengan el valor entre ejecuciones diferentes → variables estáticas en subprogramas (ej. static en C)

5.2.1.2. Ventaja principal: eficiencia - Todas pueden tener direccionamiento directo (otros tipos de variable necesitan direccionamiento indirecto que es más lento) - No hay sobrecarga en tiempo de ejecución por asignación o desasignación de espacio

5.2.1.3. Desventaja: reducida flexibilidad Si un LP no dispone de otro tipo de variables ⇒ no se soportan programas recursivos

5.2.2. B. Variables dinámicas de pila

5.2.2.1. La ligadura de espacio se produce cuando se elabora la sentencia de declaración, exceptuando las que se ligan estáticamente

5.2.2.2. Elaboración de una sentencia de declaración: proceso de asignación y ligadura de espacio indicada por la declaración que tiene lugar cuando la ejecución alcanza el código de dicha declaración ⇒ la elaboración se produce en tiempo de ejecución

5.2.2.3. El espacio se asigna en la pila de tiempo de ejecución -Las variables locales (declaradas en subprogramas) son variables dinámicas de pila (a excepción de las declaradas como estáticas)

5.2.2.4. Ventajas: - Todas las variables comparten el mismo espacio de memoria (la pila) - Permiten recursión → permite almacenar una copia diferente de las variables locales para cada una de las llamadas recursivas

5.2.2.5. Desventaja: - Sobrecarga en tiempo de ejecución debido a la asignación y desasignación de espacio en la pila

5.2.3. C. variables dinámicas de montón (heap)

5.2.3.1. Montón (heap): colección de celdas de almacenamiento cuya estructura está muy desorganizada debido a la naturaleza imprevisible de su uso

5.2.3.1.1. C.1 Explícitas

5.2.3.1.2. C.2 Implícitas

6. 3. Tipos

6.1. 3.1 Comprobación de tipos

6.1.1. Generalización de los conceptos de operandos y operadores para incluir a subprogramas y sentencia de asignación:

6.1.1.1. Subprogramas → operadores cuyos operandos son sus parámetros

6.1.1.2. Asignación → operador binario cuyos operandos son la variable a la que se asigna el valor y la expresión a evaluar

6.1.2. Comprobación de tipos: actividad que nos asegura que los operandos de un operador son de tipos compatibles

6.1.3. Tipos compatibles: un tipo legal para el operador o un tipo que atendiendo a determinadas reglas del lenguaje puede ser convertido implícitamente mediante código generado por el compilador en un tipo legal. Esta conversión automática se denomina coacción (coercion)

6.1.4. Error de tipos: aplicación de un operador a un operando de tipo inapropiado

6.1.5. Si todas las ligaduras de tipos a variables son estáticas ⇒ las comprobaciones de tipo pueden realizarse de forma estática

6.1.6. Si hay ligadura dinámica de tipos a variables ⇒ debe realizarse una comprobación dinámica de tipos (más costosa que en tiempo de compilación)

6.2. 3.2 Disciplina de tipos

6.2.1. Un lenguaje tiene disciplina de tipos si los errores de tipos se detectan siempre ⇒ es necesario determinar los tipos de todos los operandos, ya sea en tiempo de compilación o de ejecución

6.2.2. Pascal Cercano a tener disciplina de tipos pero no realiza comprobación de tipos en los registros variantes (incluso puede omitirse la etiqueta discriminatoria en dichos registros)

6.2.3. Ada - Resuelve el problema de los registros variantes realizando comprobación dinámica de tipos (sólo en este caso) - Tiene una función de biblioteca que permite extraer un valor de una variable de cualquier tipo (como una cadena de bits) y usarlo como un tipo diferente (no es una conversión de tipos) ⇒ se trata de una suspensión temporal de la comprobación de tipos

6.2.4. C No tiene disciplina de tipos por: − No se realiza comprobación de tipos sobre las uniones − Permite funciones con parámetros sobre los que no se realiza comprobación de tipos

6.2.5. Java - Tiene disciplina de tipos (no hay uniones) ♦ ML y Haskell - Poseen disciplina de tipos - Los tipos de los parámetros de las funciones (y de estas mismas) se conocen en tiempo de compilación (ya sea por declaración del usuario o por inferencia de tipos)

6.3. 3.3 Compatibilidad de tipos

6.3.1. Métodos

6.3.1.1. Compatibilidad de tipos nominal: dos variables tienen tipos compatibles si están ligadas al mismo nombre de tipo

6.3.1.2. Compatibilidad de tipos estructural: dos variables tienen tipos compatibles si sus tipos tienen la misma estructura

6.3.1.3. Equivalencia de declaración: dos variables tienen tipos compatibles si uno de los tipos está definido con el nombre del otro

6.3.2. La mayoría de LP utilizan combinaciones de estos tres métodos de compatibilidad

6.3.3. Tipo anónimo: tipo asociado directamente con una variable mediante una declaración sin proporcionarle un nombre

6.3.4. Compatibilidad de tipos nominal: - Fácil de implementar pero muy restrictiva Ej. usando un lenguaje con interpretación estricta de la compatibilidad de tipos nominal:

6.3.5. Compatibilidad de tipos estructural:

6.3.5.1. + Debe compararse la estructura de ambos tipos, pero: − ¿Son compatibles dos registros con la misma estructura pero con nombres de campos diferentes? − ¿Son compatibles arrays del mismo tipo y con el mismo número de elementos pero con rangos de índices diferentes (0..9 / 1..10)? − ¿Son compatibles tipos enumerados con el mismo número de componentes pero literales diferentes? 

6.3.5.2. No acepta diferencias entre tipos con la misma estructura

6.3.6. Subtipo: versión (posiblemente restringida en el rango) de un tipo existente con el que es compatible. Evita uno de los problemas de la compatibilidad de tipos nominal

6.3.7. Tipo derivado: nuevo tipo basado en algún otro previamente definido con el que es incompatible, aunque sean estructuralmente idénticos. Heredan todas las propiedades de su tipo padre. (También pueden incluir restricciones sobre el rango)