Introducción: Play Framework 2 (Parte I: Scala)

Para aquellos que no lo conozcan, Play es un Framework de desarrollo web para Java y Scala. Ha sido desarrollado por Guillaume Bort como proyecto interno para su empresa Zenexity y luego liberado como Open Source.

A partir de la versión 2.0 del mismo, Martin Odersky y su compañía TypeSafe que a su vez son los creadores de Scala han decidido incluirlo en el paquete que denominan TypeSafe Stack.

Como ya hemos dicho, Play puede ser utilizado para construir sitios y aplicaciones web tanto en Java como en Scala comparten gran parte de la API ya que Scala puede importar y utilizar librerías de Java sin problemas.

Pero antes de hacer una pequeña introducción al framework es necesario hablar sobre que es Scala y por qué es “especial“. Esta guía introductoria no pretende ser una guía exhaustiva del lenguaje de programación Scala, tal tarea es algo que se escapa a mis pretensiones y mi inteligencia.

¿Qué es Scala?


Scala es un lenguaje de programación multiparadigma diseñado para integrar características de la programación orientada a objetos y de la programación funcional. Aunque nuestra primera reacción es pensar que ambos paradigmas son excluyentes, lo cierto es que Scala ha sabido mezclarlos de manera muy sutil con un gran resultado.

Scala es de tipado estático fuerte y por lo tanto debe compilarse aunque también puede utilizarse a modo de scripts utilizando el “intérprete” de línea de comandos para ejecutar pequeños programas escritos en él sin necesidad de compilar previamente a bytecode los mismos.

Scala nos permite programar de forma imperativa, funcional o ambas a la vez. Por ejemplo, podemos utilizar Polimorfismo clásico de la orientación a objetos o bien pattern matching para resolver el mismo problema. Podemos usar uno u otro paradigma dependiendo de si la solución que plantea parece la más adecuada a la hora de resolver el problema al que nos estamos enfrentando.

En Scala, así como en todos los lenguajes que soportan la programación funcional (incluso PHP después de su versión 5.3.1) las funciones son ciudadanos de primer orden (o first-class) dentro del lenguaje y por lo tanto pueden ser creadas utilizando literales que después pueden ser pasados como parámetros y devueltos por otras funciones.

En Scala además los tipos son inferidos aunque también pueden ser definidos de forma explicita. Por ejemplo:

val uno = 1
val dos: Int = 2
Ambas declaraciones son válidas. En el primer caso el tipo de la variable (aunque inmutable) uno es Int ya que es inferido por el compilador.

Scala se ejecuta sobre la máquina virtual de Java (JVM) y/o la máquina virtual de .NET (CLR), también puede correr sobre Dalvik en la plataforma Android. Tanto el compilador como las librerías se distribuyen bajo una licencia BSD.

El REPL


Scala viene con una especie de intérprete conocido como el REPL (Read, Evaluate, Print, Loop) que puede ser ejecutado desde el terminal al instalar el lenguaje en nuestro sistema. Para acceder a él tan solo tenemos que escribir el comando scala en la línea de comandos de nuestro sistema operativo.

En el caso de Windows es posible que primero necesites añadir la ruta al directorio de los binarios de Scala al PATH del sistema.

Programación Orientada a Objetos


Scala es un lenguaje orientado a objetos puro, es decir, todo en Scala es un objeto. Las estructuras de datos así como los métodos que definen su comportamiento están descritos por clases y traits. Así definiríamos una clase en Scala:

class User {
    private var name = "Perico"
    private var lastname = "Los Palotes"
    // En Scala se usa la palabra reservada def (como en Python)
    // para declarar un método o función
    def fullname(): String = {
        name + " " + lastname
    }
}
val perico = new User
perico.fullname

Habréis notado la ausencia de la palabra reservada return en el ejemplo anterior, en Scala la última expresión que aparece en una función es usada como su valor de retorno. Los punto y coma son opcionales.

El cuerpo de una función no es obligatorio en Scala si, como en nuestro ejemplo, la función solo ejecuta una expresión. Podríamos haber reducido nuestro código declarando el método fullname de la siguiente forma:

def fullname(): String = name + " " + lastname
Tambień podríamos haber obviado el tipo del valor de retorno (String) que habría sido inferido de forma automática.

Scala es más estricto en su orientación a objetos que Java o C++ y las clases no soportan métodos estáticos por lo que el lenguaje hace uso de objetos singleton. La definición de un objeto singleton se parece a la definición de una clase excepto que en lugar de usar la palabra reservada class usamos la palabra reservada object.

Scala soporta la extensión de tipos mediante herencia simple así como un mecanismo de composición basado en mixins usando traits. Asimismo Scala incorpora reglas de visibilidad para ocultar el scope de los métodos y/o propiedades a través de las palabras reservadas public, protected y private.

Podemos sobreescribir métodos de clases y traits utilizando la palabra reservada override. Podemos declarar los tipos como finales para que no puedan sobreescribirse o abstractos para lo contrario.

La implementación de la orientación a objetos en Scala es bastante peculiar, por ejemplo existen los companion objects y las case clases recomiendo echar un ojo a la página de Scala para ampliar esta muy escueta información.

Programación Funcional


Scala soporta plenamente la programación funcional aunque no exento de problema. Por ejemplo la optimización de recursión (convertir una función recursiva a un loop eliminando posibles stack overflow y la sobrecarga de la llamada a función) con tail calls (subrutina que aparece en una función como su última instrucción) no está soportada de forma nativa por la JVM, el compilador de Scala (scalac) si lo hace.

Dentro del estilo de programación funcional encontramos implementadas las siguientes:

  • Inmutablidad: Scala soporta las variables inmutables a través de la palabra reservada val

  • Funciones First Class: Las funciones son ciudadanas de primera clase

  • Closures: Se pueden definir y utilizar closures y clases anidadas

  • Traversing, Mapping, Filtering, Folding y Reducing: Operaciones que no producen efectos secundarios en las colecciones

  • Pattern Matching: Pieza fundamental en los lenguajes funcionales

  • Partial Functions: Expresiones en las que no todos los argumentos definidos en una función son pasados a la función

  • Currying: Convierte una función que toma múltiples argumentos en una cadena de funciones que toman un único argumento

  • Implicit: Algunas veces es necesario usar un tipo en un contexto diferente pero similar al tipo real requerido para ello se usa la palabra reservada implicit

  • Lazy vals: Inicialización vaga de variables

Actores


Scala implementa la concurrencia a través de los llamados actores que inspirados por el trabajo de Carl Hewitt, Peter Bishop, y Richard Steiger en A Universal Modular Actor Formalism for Artificial Intelligence y la implementación de estos en el lenguaje Erlang.

En su forma más básica, los Actores en Scala son objetos que heredan de scala.actors.Actor y ejecutan alguna función:

import scala.actors.Actor
class WorkerDog extends Actor { def talk() { println("Woof woof… and this is a side effect :(") } def act = talk
}
val toby = new WorkerDog
toby.start

Esto es bastante similar a la forma en la que usaríamos un Thread en otro lenguaje como por ejemplo Python o Java.

Conclusión


Aunque en Scala se puede programar de forma imperativa, es recomendable ir utilizando una forma más funcional conforme nos vamos sintiendo cómodos con el lenguaje aunque eso de la comodidad va a tardar en llegar. Scala es un lenguaje complejo y enrevesado con una curva de aprendizaje brutal y en muchos casos desalentadora.

Recomiendo echarle un ojo en serio a la documentación de Scala y a la página de Play Framework.

Más en Genbeta Dev | Diferencias entre paradigmas de programación

Portada de Genbeta