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.

Entradas relacionadas:

3 Responses to “Jugueteando con Scala”

  1. Morfeo Says:

    Es interesante como intentas “forzar” conceptos como el “pattern matching”(https://en.wikipedia.org/wiki/Pattern_matching) o los “traits” (https://en.wikipedia.org/wiki/Trait_%28computer_programming%29) para hacerlos coincidir con tus “ideas Javeras”.

    Te recomiendo que profundices mucho más en los paradigmas de programación “orientado a objetos puro”, preferente con SmallTalk (https://en.wikipedia.org/wiki/Smalltalk) donde tus queridos “switch case” (incluso los “if”) no existen (son considerados “harmful” como el “goto”, jeje, https://en.wikipedia.org/wiki/Considered_harmful).

    Es que se trata, no sólo de un cambio de sintaxis, sino de PARADIGMA (aunque tu POO se ve demasiado “estructurada” (https://en.wikipedia.org/wiki/Structured_programming) con tanto switch/if/elseif).

    Pero sobre todo te recomiendo que te interiorices en el paradigma “FUNCIONAL”(https://en.wikipedia.org/wiki/Functional_programming), en el que está basado principalmente Scala(https://en.wikipedia.org/wiki/Scala_%28programming_language%29#Case_classes_and_pattern_matching).

    Un buen inicio es aprender Haskel (http://aprendehaskell.es/) por el bien de todos…
    … y dejar de pensar que todo se traduce a Java!!!

    Gracias, es sólo un consejo, saludos!

  2. Poza Says:

    Hola, sólo un comentario a un artículo interesante. Hablas de que Scala tiene visibilidad de paquete y Java no. Es incierto, los métodos y variables con modificador default (sin modificador de visibilidad)lo hace visible únicamente en el paquete.

  3. Chuidiang Says:

    @Poza, cierto, quizás me expresé mal, con cosas como public[cualquier.paquete] puedes hacer que las clases de tu paquete sena públicas, por ejemplo, para otro paquete y sólo para él.

    Se bueno.

Leave a Reply