En un post anterior Rolando propuso en base a algunas referencias el uso de Python para la enseñanza de la programación. Se argumenta que el "duck typing" puede ser una de sus características principales.
Primero es lo primero, expliquemos que es duck typing, que no es más que una forma ordenada de tener tipos dinámicos. Básicamente en una expresión escrita en un lenguaje que tiene duck typing, la interpretación de la expresión depende de los objetos reales que han sido instanciados para esa expresión. Bruce Eckel tiene algunos ejemplos entretenidos en su blog: I´m over it, About Latent Typing y Generics Aren't. Uno de ellos está en Python. Supongamos que tenemos la siguiente definición:
def speak(anything):
anything.talk()
La variable anything es un parámetro y no hay referencia al tipo de ella. En realidad puede ser cualquier cosa, siempre y cuando pueda responder al método talk(). Esto implica que existe una noción implícita de interfaz que debe satisfacerse. Eso es lo que Eckel llama latent typing. Supongamos entonces que creamos las clases:
class Dog:
def talk(self): print "Arf!"
def reproduce(self): pass
class Robot:
def talk(self): print "Click!"
def oilChange(self): pass
entonces es posible ahora dar una interpretación a la expresión:
speak(b)
siempre y cuando haya una definición de lo que es b. Por ejemplo
b = Dog()
o cuando se tenga:
b = Robot()
Creo que la característica es interesante, pero no sé si es algo bueno para aprendices. En la definición de speak() la definición de que anything representa a un tipo con restricciones (la interfaz) está implícita y resulta algo mágico. La interfaz no tiene nombre y no se puede usar en otros contextos donde tal vez sea necesaria. Queda oculta parte de la estructura del programa y ni siquiera se puede razonar sobre ella o percibir sus propiedades.
Palabras clave: duck typing, programación, python, tipos
Comentarios
Hola Pablo! Podrías poner un ejemplo de como sería "razonar sobre ella"?
Por otra parte no me gusta el nombre de "duck typing", da la impresión que sería algo más avanzado que tipado dinámico, cuando en realidad es lo mismo :).
En:
deberías pensar que en realidad lo que quieres expresar es (haskelleando un poco )
speak :: Restriccion a => a -> b
y posiblemente haya una relación mucho más fuerte entre el tipo de anything a y el del resultado b. Haskelleando un poco más:
class Restriccion a where
talk :: a -> b
o algo asi, no te parece? En el blog de Eckel (generics aren't) se muestra como es la cosa en Java, y se explicita la relación de los tipos. En este ejemplo en Python, Restriccion no tiene nombre y está escondida en una definición muy particular.
Al discutir este ejemplo Eckel se da cuenta que en realidad en Java no hay polimorfismo paramétrico y se pone a renegar contra las genéricas. En realidad se pone a razonar sobre los tipos y las propiedades de ellos y descubre otras dimensiones.
Esta es una forma muy sencilla de "razonar". Sin embargo no la única. Es posible que también quieras definir propiedades más formales sobre tus tipos. Esas serían otras dimensiones de razonamiento.
Creo que programar se trata de descubrir las abstracciones y no secuenciar las instrucciones. En este sentido, cada paso que das en descubrir una nueva abstracción es interesante poderla definir en tu programa. Los lenguajes con tipos dinámicos son interesantes porque te permiten prototipar tus ideas, pero no entenderlas. En los lenguajes con tipos estáticos, la programación de las estructuras forma parte del razonamiento de programación. Los lenguajes con tipeo implícito como Haskell (deducción de tipos) son un balance intermedio que te permite escribir tus expresiones sin pensar demasiado, pero una vez que has podido descubrir algo puedes querer mirar su tipo. A veces descubres que tienes una función polimórfica sin querer, es decir sin querer tienes algo más abstracto que te suele ser útil en otros contextos.
La idea de usar el término "duck typing" no ha sido la de popularizar el término sino la de explicarlo. Si quieres puedes explicar qué es tipado dinámico para que alguien de la audiencia se pueda enganchar en este intercambio de ideas.A ver como me sale el tipado dinámico...
Un programa es un pedazo de texto que para que haga algo útil hay que "ejecutarlo", esto puede implicar invocar el ejecutable o invocar el interprete (ej, python) sobre el programa. Los eventos que se llevan a cabo durante la ejecución del programa, se dice que son dinámicos. Por ejemplo, si el programa se detiene a causa de error de tipos es porque los tipos se verifican durante la ejecución, y por eso se llama tipado dinámico.
Un ejemplo en python:
$ python
>>> def bla():
... print "viborita"
...
>>> bla()
viborita
La funcion bla produce sabiduria en la consola pero no devuelve nada. Pero que pasa si al resultado de bla le sumamos uno?
>>> (bla())+1
viborita
Traceback (most recent call last):
File "<stdin>", line 1, in ?
TypeError: unsupported operand type(s) for +: 'NoneType' and 'int'
Aja, Error! Pero python tuvo que EJECUTAR bla para darse cuenta que no devuelve nada y eso queridos amigos significa tipado dinamico!
En un lenguaje con tipado estatico, la verificacion ocurre ANTES de ejecutar el programa, de hecho no es necesario ejecutar el programa. Un ejemplo con Haskell:
$ ghci
Prelude> let bla = putStrLn "the beast"
Prelude> bla
the beast
Prelude> bla + 1
<interactive>:1:4:
No instance for (Num (IO ()))
arising from use of `+' at <interactive>:1:4
Probable fix: add an instance declaration for (Num (IO ()))
In the definition of `it': it = bla + 1
Prelude>
Como pueden apreciar sus ilustres mercedes, el mensaje en bla no se imprime ya que el programa no tiene tipos correctos y no se ejecuta en absoluto. Tipado estático.
En el siguiente comentario trataré de hablar sobre duck typing.
P.S. Como se escribe codigo en este editor?
Aún mejor, en la version 3.0 de nuestro programa (o XP, váyase uno a saber) la función speak tiene 200 líneas de código, que gusto tener que leerlas cada vez que uno vaya a llamarla :).
El siguiente paso por supuesto es poner un comentario arriba de la definición explicando que objetos speak va a recibir. Esto amigos míos es información estática que está en el cerebro del programador. El o ella sabe que objetos se pueden pasar a speak y esto debe complirse para TODAS las ejecuciones posibles del programa. O sea que existe una información de los tipos aceptables pero expresado de una manera informal en un comentario.
Como todos sabemos los comentarios en la versión 5.0 o Longhorn ya no están al día y habrá que hacer fallar el programa dinámicamente para detectar que hay algo inconsistente.
Ya que la información es estática porque no usar la computadora para ayudarnos a detectar inconsistencias? Eso es lo que intentan los sistemas de tipos. Lamentablemente las computadoras no pueden leer nuestros cerebros por lo que tenemos que inventar lenguajes para expresar información estática. Y mientras más poderoso el sistema de tipos, más complejo se vuelve. Este es el precio a pagar por tenerlos.
No estoy criticando nada al mensaje de Pablo :), creo que el opina de manera similar, solo quería desahogarme un poco.
Creo que es legítimo enseñar lenguajes con tipado dinámico para evitar la complejidad de tipos estáticos inicialmente. Después de todo aprendí a programar con GW-Basic :).
Me parece chistoso que en una comunidad java estemos usando Python como ejemplo :-)
Creo que este editor no es para programadores. He puesto PRE en HTML y no funciona ...
... return 'viborita rulz!'
Creo que es lo mismo, pero haskell tiene valor de retorno "void"? o None?...
>>> blah()
'viborita rulz!'
>>> (blah())+1
Traceback (most recent call last):
File "<stdin>", line 1, in ?
TypeError: cannot concatenate 'str' and 'int' objects
Hasta donde sabía, python tenía tipado fuerte y dinámico. Perl por ejemplo tipado debil y dinámico, c tipado fuerte y estático. Estoy correcto?
Ahora el siguiente ejemplo:
$ cat /tmp/test.c
#include <stdio.h>
int blah(void){printf("printfn"); return 1;}
int main(int argc, char *argv)
{
char *ptr = "a";
printf("%sn", (blah() + *ptr++) );
return 0;
}
$ gcc /tmp/test.c
$ ./a.out
printf
Violación de segmento
O_o
Si fuera pregunta de examen, por que falla el programa? (cual sería la respuesta?)
PD: Escribiría en java si me acordara... pero mucho objeto cuando no se lo necesita.. xD