Lenguajes de Programación I
Subrutinas Genéricas - Excepciones
Ernesto Hernández-Novich
<[email protected]>
Subrutinas Genéricas
Mecanismo implícito de
Polimorfismo paramétrico
.
Declarar subrutinas con tipos incompletos pero consistentes.
Lentitud a tiempo de ejecución (LISP) o compilación compleja (Haskell).
Obliga a utilizar equivalencia estructural de tipos.
Mecanismo explícito de
Polimorfismo Genérico
.
Crear múltiples subrutinas a partir de un plantilla única. Utiles para creación decontenedores.
Definición Genérica en C++
Se declara una plantilla...
template<class item, int max_items = 100>
class queue {
item items[max_items];
...
public:
queue() { ... };
void enqueue(item it) { ... };
item dequeue() { ... }
}
...que se usa para crear específicos
queue<int,50> int_queue;
queue<process> ready_list;
Implantación puramente estática
El compilador crea copias separadas de código por cada
instanciación (Ada, C++).
El código de los métodos podría ser común a instancias
del mismo tipo.
Algunos lenguajes
garantizan
que todas las instancias
comparten código a tiempo de ejecución (Java 5).
¡No son macros!
Están integrados en el lenguaje.
Los tipos de los parámetros son verificados. Los argumentos son evaluados una sola vez. Las reglas de alcance aplican normalmente.
Restricciones en la parametrización
La interfaz o cabecera de declaración provee toda la
información necesaria al programador usuario.
Las restricciones obligan al programador a usar la plantilla
de forma particular
Restringiendo las operaciones disponibles. Con tipos que provean determinados métodos.
Excepciones
Es una condición inesperada o inusual, que surge durante
la ejecución del programa y no puede ser manejada en el
contexto local.
Detectada implícitamente vs. generada (
raised
)
explícitamente.
El programador tiene tres opciones (todas mediocres):
1 Inventar un valor que el llamador pueda utilizar en lugar de un valor válido.
2 Retornar un valor de estado al llamador, que debe verificarlo.
3 Pasar una clausura para una rutina que maneje errores.
El manejo de excepciones resuelve el problema...
...haciendo el caso normal simple de expresar,
y logrando que el flujo de control vaya a unmanejador de excepcionescuando sea necesario.
Aproximación a las Excepciones
Originalmente, se disponía de ejecución condicionada
(PL/I)
ON condición
instrucciones
Los lenguajes modernos ofrecen bloques léxicos.
El bloque de código para el caso normal.
Un bloque contigüo para las excepciones quereemplazala ejecución del resto del bloque en caso de error.
Manejador de Excepciones
En C++
try {
// Caso normal
}
catch (...) {
// Manejador
}
En Perl
eval {
# Caso normal
}
if ($@) {
# Manejador
}
¿Qué se hace en el Manejador de Excepciones?
1
Si la excepción es recuperable, intenta recuperarse para
continuar.
2
Si la excepción no puede ser recuperada en el bloque
local, realiza la limpieza necesario y luego propaga la
excepción.
3
Si no puede recuperarse, al menos emite un mensaje de
¿Cómo se definen las Excepciones?
Los errores semánticos dinámicos resultan en
excepciones que los programas pueden atrapar.
El programador puede definir sus propias excepciones.
A través de un tipo predefinido en el lenguaje (Ada, Modula-3).
Creando un tipo ordinario (Python, C++, Java).
Aproximación mixta (tipo base simple vs. librerías, Perl).
Las excepciones pueden parametrizarse.
Se lanzan con instrucciones especiales.
raise(Ada, Modula-3, Python). throw(Java, C++).
Implantación Obvia
Pila de listas de manejadores.
Al entrar a un bloque protegido, se agrega el manejador al principio de la lista.
Cuando ocurre una excepción, se observa el tope de la pila y se utilizan los manejadores en orden.
Cada subrutina cuenta con un manejador implícito que ejecuta el epílogo y propaga la excepción.
Esta solución incurre en un costo muy alto, incluso para el
caso
normal
.
Agregar manejador a la lista, al entrar a la rutina. Eliminar manejador de la lista, al salir de la rutina.
Implantación Inteligente
Generar una tabla de manejadores a tiempo de
compilación.
Cada entradas tiene dos direcciones Dirección de inicio del bloque. Dirección de inicio del manejador. Se ordenan por el primer elemento. Si ocurre una excepción
Búsqueda binaria de la dirección actual usando elprogram counter.
Si se propaga la excepción, se repite la búsqueda.
El costo de ejecución aument cuando ocurre una
excepción, pero el caso normal no incurre en costo de
ejecución.
Excepciones sin excepciones
Pueden simularse en algunos lenguajes.
gotoa etiquetas fuera de la subrutina actual (Pascal). call-with-current-continuation(Scheme)
Es una funcióncall/ccque recibe una funciónf. Llama afpasando una clausura que captura elprogram countery ambiente de referencia.
De ser necesario,fpodríautilizar dicha clausura para reestablecer el ambiente de referencia.
La parejasetjmpylongjmp(C). if (!setjmp(buffer)) {
/* Bloque que quizás usa longjmp */ } else {
/* Manejador */ }
Co-rutinas
Co-rutina
Se representa como una clausura.
Podemos saltardentrousando una operación de transferencia(transfer).
Las transferenciasconservanel contador de programa, de modo que nuevas transferencias continúan donde habían quedado.
Son ejecuciones
Que existen concurrentemente. Ejecutan una a la vez.
Implantación
Pila de ejecución.
Cada co-rutina tiene un espacio para su pila (estático o en elheap).
Se produce un error a tiempo de ejecución si se excede. Si las co-rutinas pueden anidarse se usa una pilacactus.
Operación de transferencia.
Conservar el contador de programa, la pila y los registros. Al comenzar eltransferse empilan en el origen los registros a salvar y la dirección de retorno.
Se hace apuntar el stack pointer a la pila destino. Se desempila la dirección de retorno y los registros salvados.