Cómo minimizar las desventajas del tipado estático y capitalizar sus ventajas

Post on 04-Jul-2015

397 views 0 download

description

http://sg.com.mx/sgce/2013/sessions/c%C3%B3mo-minimizar-las-desventajas-del-tipado-est%C3%A1tico-y-capitalizar-sus-ventajas Esta será una conferencia técnica sobre lenguajes de programación donde Gavin King discutirá las ventajas y desventajas del tipado estático (static typing), mostrando cómo es que lenguajes modernos de programación como Ceylon ayudan a minimizar las desventajas al mismo tiempo que capitalizan las ventajas.

Transcript of Cómo minimizar las desventajas del tipado estático y capitalizar sus ventajas

Tipos Estáticos y Ceylon

Gavin King

http://ceylon-lang.org

Aprender Ceylon

Taller Ceylon

El sabado a las 9:30 AM

Goldsmith #40 Col. Polanco, entre Dickens y Emilio

Castelar

Con Gavin y Enrique

Acerca de Ceylon

• Nuevo lenguaje de programación

• Para máquinas virtuales– JVM y JavaScript (el entorno)

• Plataforma modular– “módulo del lenguaje” — mínimo, ligero

– otros módulos independientes del entorno

– módulos para un solo entorno (JVM, JavaScript)

Acerca de Ceylon

• Herramientas– Ceylon IDE y línea de comando

• Infraestructura para manejar y compartir los módulos– arquitectura de repositorios de módulos y dependencias

– Ceylon Herd (un repo central para la comunidad)

– entorno de módulos (JBoss Modules/CommonJS)

Expresividad

• Es muy fácil diseñar un lenguaje muy expresivo

• Por ejemplo, con los lenguajes “dinámicos” se siente como que se puede hacer casi lo que sea

• Pero con lenguajes así es muy difícil crear herramientas que nos ayuden como programadores a encontrar bugs, refactorizar y analizar el código– el compilador

– el IDE

– el compilador de documentación

Expresividad

• Para programas grandes las herramientas pueden mejorar mucho la productividad

• Por lo tanto necesitamos un lenguaje con reglas– Estas reglas nos estorban para expresarnos!

– Pero cuando están bien diseñadas frecuentemente nos ayudan a llegar a un diseño más elegante y más robusto

– Ademas, las herramientas y las reglas nos ayudan a comprender el código horrible que han hecho nuestros compañeros locos! (Gasto mucho mas tiempo en leer el código de otros que en escribir mi propio código)

Limites de expresividad

• Siempre podemos aumentar la expresividad de un lenguaje añadiendo características, introduciendo nuevas reglas especiales, nueva sintaxis

• Al final llegamos a tener un lenguaje tan complicado que el programador no sabe todas las reglas, ni puede reproducir el razonamiento del compilador, ni entiende el código de otros o de las bibliotecas que utiliza

• También hay limites básicos de decidibilidad que restringen el razonamiento del compilador

Objetos y tipos estáticos

• Un lenguaje orientado a objetos es un lenguaje con polimorfismo de subtipos

• Cuando combinamos subtipos con un sistema de tipos estáticos, llegamos muy rápido al problema de tipos contenedores (colecciones)

• Para modelar el contrato de un tipo contenedor hay que introducir polimorfismo paramétrico (generics)– Entonces encontramos las dos variedades de

polimorfismo en Java, C#, C++, Ceylon, Scala, ...

Objetos y tipos estáticos

• La mala noticia: un sistema de tipos con la combinación de los dos polimorfismos es necesariamente bastante complejo– Abandonamos objetos? Abandonamos tipos estáticos?

No! Al final vale la pena

• En cambio, buscamos cómo presentarlo de manera más digerible y eliminar la complejidad innecesaria– Qué ofrece la nueva generación de lenguajes con tipos

estáticos? Pues que son los puntos dolorosos?

Los puntos dolorosos

• Declarar tipos resulta en verbosidad

• Abstraer sobre tipos que no controlamos– por ejemplo, tipos definidos en otros módulos que no

tienen ningún supertipo en común

• Varianza con wildcards

• Tratar con funciones como valores y abstraer sobre tipos de funciones– para definir funciones genéricas de orden superior

• El valor null y la maldita NullPointerException

Verbosidad

• Poner el tipo como int, bool, char no cuesta mucho, pero ahora, con generics, tratamos con tipos como

Map<String,WeakRef<Object?>>String|{Character*}

• Inferencia de tipos (alcance local)value weakRefMap = Map { key1 -> WeakRef(val1),

key2 -> WeakRef(val2) };

• Aliases de tiposalias WeakRefMap => Map<String,WeakRef<Object?>>;alias Stringish => String|{Character*};

Uniones, intersecciones

• A veces encontramos casos como– print() que acepta un String, Integer, o Float

– readLine() que produce un String, EOF o Error

– send() que acepta algo que es Persistent y Serializable

• Malas soluciones: – usar Object

– sobrecargar print()

– crear una clase intermedia (algun tipo de wrapper)

– En un lenguaje dinámico no necesitamos nada así

Uniones, intersecciones

• Mejor solución con tipos unión e intersección– void print(String|Integer|Float line) { ... }

– String|EOF|Error readLine() { ... }

– void send(Persistent&Serializable message) { ... }

• De hecho, uniones e intersecciones nos ayudan mucho a simplificar el sistema de tipos y hacerlo más elegante y más completo– Les van a encantar, lo prometo

Varianza

• Covarianza: intuitivamente un Set<Integer> es un Set<Number>

– también tenemos contravarianza

• Mala solución: wildcards de Java– el Set<Integer> es un Set<? extends Number>

– casi nadie los entiende completamente

– resultan en errores muy confusos

– bastante verboso

Varianza

• Mejor solución con varianza de lado de declaración

• Declaramos la varianza del tipo donde lo definimos– covariante out, contravariante in

– interface Set<out T> { ... }

– el compilador verifica que el tipo sí es verdaderamente covariante o contravariante

• Cuando utilizamos el tipo, todo funciona como intuitivamente esperamos– ahora Set<Integer> sí es un Set<Number>

Null y Nothing

• Socavamos el sistema entero cuando ponemos hoyos para “conveniencia”– NullPointerException es una excepción de tipo en

tiempo de ejecución como tienes con los tipos dinámicos!

• El tipo bottom o Nothing es un subtipo de todo tipo– Corresponde al conjunto vacío en matemáticas

– Entonces el tipo bottom no tiene ningún valor

– Excepto en Java, C#, Scala ... donde tiene el valor null

– Oops.

Null y Nothing

• En Ceylon, el tipo Nothing no tiene ningún valor

• Tenemos una clase Null perfectamente ordinaria con un único valor null– Escribimos “un string o null” como String|Null

– O lo abreviamos como String?

• El compilador verifica que cada valor ha sido inicializado antes de ser utilizado– para no encontrar valores no inicializados en tiempo de

ejecución

• Ninguna NullPointerException ocurre jamás!

Acotamiento de tipos

• Cómo podemos obtener un String si tenemos un valor de tipo String?– un caso especial del problema de acotamiento

• El tipo de un valor puede cambiar con el flujo de código condicional

• Ya no necesitamos los casts inseguros de C

String? name = process.arguments[0];if (exists name) { //aquí, name es de tipo String print(“Hello, “ + name + “!”);}

Funciones y tuplas

• Cómo podemos representar el tipo de una tupla por ejemplo [0.0, 0.0, “origen”]

• Luego, cómo representar el tipo de una función– combina un tipo de tupla con otro tipo

• Definimos Tuple y Callable como clases ordinarias y proveemos azúcar sintáctica– tipo de tupla: [Float, Float, String]

– tipo de función: Point(Float, Float, String)

• Nos deja definir funciones de orden superior incluso funciones genéricas como compose()

La mala noticia

• El sistema de inferencia de tipos funciona bien sin ambigüedades gracias al concepto de tipos principales– Cada expresión tiene su único tipo más específico, su

tipo principal (frecuentemente expresado con el uso de unión y intersección)

• Funciones sobrecargadas rompen el sistema de tipos principales– Una función sobrecargada no tiene ningún tipo principal

– Como los lenguajes dinámicos no tenemos overloading

Conclusión

• Se puede mejorar mucho el sistema de tipos, aliviando los puntos dolorosos

• Un punto clave es ajustar el punto de vista para pensar en tipos como conjuntos

• Así podemos tratar con tipos de una manera más sofisticada, formando expresiones con | y &, introduciendo aliases, infiriendo tipos complejos

• El problema de decidibilidad limita lo que podemos hacer

Conclusión

• La nueva generación de lenguajes de tipado estático es mucho más expresiva

• Puede ser tan expresivo y flexible como un lenguaje dinámico? No!– O, más bien, expresa cosas diferentes (tipos)

• Aún vale la pena — tipado estático tiene sus propias ventajas, facilita herramientas!

Preguntas

http://ceylon-lang.org

Taller CeylonEl sabado a las 9:30 AM

Goldsmith #40 Col. Polanco, entre Dickens y Emilio Castelar