Ambiente de Referencia Aliases y Sobrecarga Lenguajes de Programación I Clausuras, Alias y Sobrecarga Ernesto Hernández-Novich <[email protected]> c 2007-2010 Copyright Ambiente de Referencia Aliases y Sobrecarga ¿Qué clase de valor tienes? En general, en un lenguaje de programación se habla de la clase de un valor. Valores de Primera Clase Se pueden asignar a variables. Se pueden pasar como argumentos. Se pueden retornar como resultados. Todo tipo primitivo: números, caracteres, . . . Valores de Segunda Clase Se puede pasar como parámetro. Subrutinas en la mayoría de los lenguajes. Valores de Tercera Clase Ninguna de las tres cosas. Las etiquetas en la mayoría de los lenguajes. Excepciones a esta clasificación agregan flexibilidad pero agregan problemas interesantes en cuanto al alcance. Ambiente de Referencia Aliases y Sobrecarga ¿Y si el valor es una subrutina...? Es habitual asociar un nombre a una subrutina para invocarla – ¿y si usamos el nombre como un valor que haga referencia a ella? En lenguajes como Haskell, Lisp y Perl esto es posible – las subrutinas son objetos de primera clase. Es posible crear subrutinas con o sin nombre – cuando no tienen nombre se llaman lambdas. Es posible invocarlas de manera directa o indirecta. Ambiente de Referencia Aliases y Sobrecarga Funciones que usan funciones como argumentos Funciones de orden superior Funciones que usan funciones como argumentos Haskell map (*2) [ 1, 3, 5, 7 ] Perl @pares = map { $_ * 2 } qw(1 3 5 7) Lisp/Scheme (mapcar (lambda (x) (* 2 x)) (1 3 5 7)) map y mapcar reciben una función como primer argumento y una lista como segundo argumento, para producir una lista. En los tres casos, las funciones son anónimas, aunque no tiene por qué ser así. Ambiente de Referencia Aliases y Sobrecarga ¿Qué tiene que ver con el alcance? Si se tiene un lenguaje con Alcance Estático anidado y Funciones de Primera Clase es posible que la referencia a una función sobreviva al alcance donde fue definida. En Perl sub crea_contador { my $base = shift; return sub { return $base++; } } my $desde42 = crea_contador(42); my $desde69 = crea_contador(69); ¿Qué va a pasar con $base? ¿Qué va a pasar cuando llamemos a las rutinas? Ambiente de Referencia Aliases y Sobrecarga Depende de la vida de los objetos locales La extensión de la vida de un objeto local puede ser Ilimitada (como en los lenguajes funcionales) hasta que el recolector de basura las recupere. Limitada (como en los lenguajes imperativos). Si los objetos locales son destruidos al final de cada alcance, el ambiente de referencia estaría incompleto. En lenguajes no-funcionales que quieren implantar funciones de primera clase, es necesario un mecanismo alternativo de almacenamiento para preservar el alcance. Ambiente de Referencia Aliases y Sobrecarga Dos tipos de asociaciones Asociación Profunda (Deep Binding) cuando el ambiente de referencia es asociado con el cuerpo de la función al momento de construirla. Hacer un paquete con todas las variables alcanzables estáticamente al momento de definir la función. El cuerpo de la función tiene dicho paquete asociado, y se denomina clausura (closure). Al momento de ejecutarla, se usa ese paquete. Asociación Superficial (Shallow Binding) cuando el ambiente de referencia utilizado por el cuerpo de la función es aquél vigente al momento de ejecución. Alcance Estático vs. Alcance Dinámico. Ambiente de Referencia Aliases y Sobrecarga Alias Varios nombres para un mismo elemento en un alcance. Aparecen en lenguajes que ofrecen apuntadores. Existen lenguajes que incluyen el concepto de alias explícitamente, por ejemplo en Perl: $foo = 42; *bar = *foo; print $bar; (en este caso, alias entre variables, pero aplica para arreglos, diccionarios, filehandles y funciones). Tienden a hacer los programas más confusos. Pueden impedir la generación de código óptimo. Ambiente de Referencia Aliases y Sobrecarga Alias en C void f o o ( ) { i n t a , ∗pa ; / ∗ <− ∗ / a = 0; pa = &a ; ∗pa = 4 2 ; p r i n t f ( " % d % d \ n " , a , ∗ pa ) ; } Elaboración de a y *pa pa a Ambiente de Referencia Aliases y Sobrecarga Alias en C void f o o ( ) { i n t a , ∗pa ; a = 0 ; / ∗ <− ∗ / pa = &a ; ∗pa = 4 2 ; p r i n t f ( " % d % d \ n " , a , ∗ pa ) ; } Accedemos via a pa a 0 Ambiente de Referencia Aliases y Sobrecarga Alias en C void f o o ( ) { i n t a , ∗pa ; a = 0; pa = &a ; / ∗ <− ∗ / ∗pa = 4 2 ; p r i n t f ( " % d % d \ n " , a , ∗ pa ) ; } *pa apunta a a – son alias. pa a 0 Ambiente de Referencia Aliases y Sobrecarga Alias en C void f o o ( ) { i n t a , ∗pa ; a = 0; pa = &a ; ∗pa = 4 2 ; / ∗ <− ∗ / p r i n t f ( " % d % d \ n " , a , ∗ pa ) ; } Modificamos via *pa. pa a 42 Ambiente de Referencia Aliases y Sobrecarga Alias en C void f o o ( ) { i n t a , ∗pa ; a = 0; pa = &a ; pa ∗pa = 4 2 ; p r i n t f ( " % d % d \ n " , a , ∗ pa ) ; / ∗ <− ∗ / a } 42 42 42 Ambiente de Referencia Aliases y Sobrecarga Sobrecarga Ambiguedad uno a muchos Nombre único para varios elementos en un alcance. Se dice que el nombre está sobrecargado. Casi cualquier lenguaje tiene algún nombre sobrecargado, e.g. el + en C, el new en Java. La sobrecarga puede estar establecida en el lenguaje como consecuencia de su diseño, pero también puede estar disponible al programador. Sobrecargar funciones. Sobrecargar operadores. Ambiente de Referencia Aliases y Sobrecarga Sobrecarga de Funciones Algunos lenguajes (C++, Java) tienen mecanismos para sobrecargar nombres de subrutinas. Mismo nombre, pero diferente número o tipo de argumentos. La firma de cada subrutina debe ser diferente. La firma se analiza para determinar cuál es la función particular que debe invocarse. Ambiente de Referencia Aliases y Sobrecarga Sobrecarga de Operadores Algunos lenguajes (C++, Perl, Fortran90) permiten sobrecargar operadores aritméticos con funciones definidas por el usuario. Típicamente se asocia a un método de una clase para agregar esa carga semántica al mismo símbolo. Definir una clase Complex para números complejos. Definir el método Complex add_complex(Complex) para sumar un número complejo a una instancia. Asociar dicho método al símbolo + del lenguaje para poder escribir cosas como a Complex; b Complex; c Complex; c = a + b // c = a.add_complex(b) Ambiente de Referencia Aliases y Sobrecarga Cuando otras cosas parecen sobrecarga Algunos lenguajes (Haskell) permiten definir funciones en las cuales los tipos a recibir son arbitrarios siempre que su uso sea consistente. Esto es útil para definir funciones genéricas que pueden operar con argumentos que cumplan con las restricciones Ya vimos la función map. Su primer argumento es una función. Su segundo argumento es una lista. map opera sin problemas siempre y cuando la función pasada como argumento, pueda operar sobre objetos como los que contiene la lista. Esto no es sobrecarga, sino polimorfismo paramétrico (que estudiaremos después). Sólo existe una función que opera sobre diferentes tipos.