May 01

Jugueteando con Scala

Tras el último post "Eligiendo lenguaje … ¿Scala?" me he puesto manos a la obra. Estoy leyendo el libro "Programming Scala" de la foto y, naturalmente, jugueteando con el IDE para Scala.

En una semana de leer y juguetear en tiempos libres, por supuesto, no he avanzado mucho, pero lo que estoy viendo me gusta bastante.

El compilador de Scala genera ficheros .class compatibles con la máquina virtual java y por tanto, es posible usar librerías compiladas con java (.jar) en Scala y es posible generar librerías (.jar) con Scala para usar en java. A mí, como programador Java, esto me facilita enormemente la vida, porque puedo introducir parcialmente Scala en mis proyectos. No, no mezclar en un mismo proyecto fuentes Java y fuentes Scala, porque no me parece elegante, pero sí crear librerías Scala que utilizaré en mis proyectos Java o viceversa.

En cuanto a la sintaxis de Scala, me da la impresión de que trata de resolver muchos de los problemas que tiene la sintaxis de Java. Aparte de ser menos verboso que Java, yo creo que lo más importante es que permite hacer cosas que Java no permite de forma fácil o simplemente no permite. Hay muchos detalles y todavía no he terminado el libro, menciono sólo algunos.

En Java la estructura de directorios tiene que coincidir con la de paquetes. En Scala no es necesario para los fuentes, aunque los .class que genera sí lo necesitan por compatibilidad. ¿Esto contribuye a desorganizar el código?. Depende de nosotros, pero de mano elimina la necesidad de crear los directorios habituales correspondientes al "dominio". Quiero decir, en mi caso todas mis clase están en el paquete "com.chuidiang" y eso en Java me obliga a meter los fuentes en un directorio "chuidiang" debajo de un directorio "com". Dos directorios "inútiles" que en Scala me puedo cepillar sin problemas.

En Java hay public, protected y private con características determinadas. En Scala se amplían estas posibilidades, ya que se permiten poner cosas como private[package] que haría el atributo/método visible no solo para la clase que lo contiene, sino para cualquier clase en el paquete, o cosas como private[this] que hace que el atributo/método sólo sea visible para esa clase, y no como en Java, que también sería visible para las clases anónimas o internas declaradas dentro de esa clase.

En Scala basta declarar una clase poniéndole parámetros en la declaración. Esto crea automáticamente el constructor con esos parámetros, los atributos privados para esos parámetros y los setter y getter (aunque sin seguir la convención java de setParametro() y getParametro()) correspondientes para esos parámetros. Desde luego, mucho menos código que en java

class Point (x:Int, y:Int) {
   // No es necesario declarar atributos x,y ni sus setter y getter
   // Scala lo hace automáticamente
   …
}

Y todo esto no dejan de ser pequeños detalles, Hay otras características muy interesantes. Por ejemplo, el switch-case en Java está bastante limitado, sólo sabe de tipos primitivos (int, char, etc), enumerados y de clases que están asociadas a estos tipos (Char, Integer, …). En los case, además, sólo se pueden poner valores constantes. El equivalente en Scala al switch-case es match, que es como el switch-case, pero a lo bestia. En el match podemos poner cualquier tipo de variable, incluidas colecciones. En los case se ponen "expresiones" predefinidas pero muy potentes. Pueden ver si la variable del "match" es de un tipo u otro, si es una colección con n elementos, si el elemento número 3 es un elemento concreto, etc, etc. Los programadores Java muchas veces hemos tenido que liarnos a if-elseif porque switch-case no es lo suficientemente potente. Otro detalle interesante de match es que devuelve un valor, el que devuelva el case correspondiente.

Otro punto muy interesante de Scala son los "trait". Un "trait" no es más que una clase que se puede añadir como "pegote" a otra clase

class UnaClase extends UnPadre with UnTrait {

}

Podemos poner varios with con varios trait en la definición de la clase, con lo que la clase tendrá como "pegotes" los métodos y atributos de los traits. No es una herencia, puesto que en la clase no haríamos llamadas estilo super.metodoDelTrait(), sino que simplemente podemos llamar a metodoDelTrait() como si fuera un método de nuestra propia clase. Esto es realmente útil y un ejemplo muy claro con el que estoy harto de tropezarme es el siguiente : Patrón Observador. Hago clases Java que tiene suscriptores a eventos que pasan dentro de esa clase. En todas esas clases tengo que poner un atributo con la lista de observadores, método addObserver(), removeObserver() y fireEvent() para avisar a los observadores. No puedo meter ese código en una clase y heredar de él porque Java no admite herencia múltiple y a veces necesito que esa clase herede de otra cosa. Ayuda algo meter esa clase que mantiene la lista de observadores como un atributo de mi clase principal, así en mi clase principal sólo debería añadir métodos addObserver() y removeObserver() que llamen a los del atributo. Pero la solución del trait es la ideal. Me basta con añadir with Observers en la declaración de mi clase para tener todo listo. Por supuesto, los trait pueden ser genéricos, de forma que la interface del observador puede ser la que queramos en cada caso, en el siguiente ejemplo, esa interface sería ButtonListener

class UnaClase extends UnPadre with Observers[ButtonListener] {

Otro detalle curioso e interesante. Si una clase tiene un método con un parámetro, en la sintaxis no es obligatorio poner el punto para llamar al método ni los paréntesis para poner el parámetro. Eligiendo adecuadamente los nombres, podemos "acercarnos" mucho a un lenguaje natural. Por ejemplo, serían equivalentes cosas como

if ( unaVariable.is(7) ) {
   …
}

if ( unaVariable is 7 ) {
   …
}

Si además ese método en vez de un boolean como en el ejemplo, devuelve otra clase que a su vez tiene un método con un parámetro, podemos encadenar llamadas y así, no es raro ver en las suite de test de Scala (similares a JUnit), cosas como 

"An empty collection" should "have size 0" in ….

En fin, sigo en ello, pero de momento es un lenguaje interesante donde los haya, con muchas posibilidades, tanto "anecdóticas" en el sentido de que sólo facilitan no escribir tanto, como de "ampliación" de lo que no es fácil o posible en Java.

Apr 25

Buscando lenguaje … ¿Scala?

scala programming language Llevo muchos años trabajando con java y llevo ya un tiempo pensando que va siendo de comenzar a aprender algún lenguaje de programación  nuevo. He jugueteado algo con python, también con groovy, trabajo con javascript con cierta frecuencia, le he echado un ojo por encima a ruby … pero son lenguajes que no me acaban de convencer.  ¿El motivo? Que no son lenguajes estáticamente tipados. Eso hace que los IDEs sean bastante deficientes a la hora de autocompletar lo que estás escribiendo, que puedas cometer errores de tecleo en las variables o métodos y no los descubras hasta tiempo de ejecución.

Dicen que son menos verbosos que java y que eso ahorra tiempo, pero tengo serias dudas si el tiempo que ahorras en escribir código no lo pierdes luego corrigiendo errores tontos de tecleo arrancando una y otra vez tu programa para descubrirlos en tiempo de ejecución. Sobre todo si el programa es un programa grande que requiera todo un montaje para arrancarlo y llegar a la zona de código que quieres probar. Sí, se que existen cosas como los test unitarios, pero también tendrías los mismos problemas de tecleo al escribir test unitarios y también sé que hay cosas que son muy difíciles de probar con test unitarios.

Por la curiosidad de aprender el lenguaje sí. Javascript, que pensaba antes de conocerlo que era un lenguaje "tonto",  me ha asombrado con sus cosas y su potencia. Entiendo que groovy, ruby, python también lo son, al menos en lo poco que he visto. Pero forma parte de mi objetivo, aparte de satisfacer mi propia curiosidad por el lenguaje, el poder darle luego una utilidad práctica en el trabajo, y la experiencia de trabajar en javascript me hace ver lo importante que es usar un lenguaje estáticamente tipado.

Ayer leí Why should I learn Scala, y creo que me ha decidido a darle una oportunidad a Scala.

Es un lenguaje del que se oye bastante últimamente y que ves que se está usando. En mis proyectos maven, cuando uso plugins o librerías de terceros, veo que rápidamente van bajándose plugins de scala y que lo usan, aunque sea por debajo. Además, es compatible con java en el sentido de que genera código compilado para la máquina virtual java, por lo que podría integrarlo fácilmente en nuestros proyectos. Sé que queda feo mezclar unos módulos en java y otros en Scala, pero es una opción para que el cambio no sea brusco.

El artículo además apoya (o al menos da importancia) mi punto de vista de la necesidad de lenguajes estáticamente tipados. Siempre es mejor encontrar errores mientras se escribe en el IDE o mientras se compila, que encontrarlos a base de probar en tiempo de ejecución.

Y el artículo además menciona un pequeño detalle con el que también tengo manía: Los setter y getter. Aunque no recuerdo dónde lo leí, decían que una ventaja de groovy era que no era necesario poner setter y getter, ya que el lenguaje los generaba automáticamente y los usaba por debajo. Pero los setter y getter tienen un motivo de existir y no son sólo para que estén. Es importante poder meter lógica más adelante en el setter o en el getter, o incluso mantenerlos tal cual aunque el atributo al que referencian cambie de tipo y/o nombre. Y parece que scala tiene contemplado ese caso. Aunque no sea necesario poner getter y setter, si es posible añadir lógica cuando se asigna un atributo e, imagino, que también cuando se lee.

Así que ayer me bajé un IDE de scala y voy a juguetear unos días a ver qué tal.