Aprende

Aprende sobre la última tecnología.

Construye

Da rienda suelta a tus conocimientos y construye!

Comparte

Que más gente lo aproveche para mejorar!
 

scala in a nutshell

jueves, 22 de enero de 2015

Ya estamos de vuelta y como dijimos en nuestra última entrada estamos ya con Scala,no vamos a decir las ventajas que tiene,para ello ya esta Ordesky así como tampoco voy  a decir las ventajas que tiene un lenguaje funcional,eso lo resolverás haciendo googling.
La instalación de Scala está aquí, basta decir que es el site del lenguaje. Desde aquí te lo puedes descargar y seguir las indicaciones de instalación. De cualquier manera si quisieras instalarlo en un linux tengo un script en github, que ha sido instalado tanto  en un Centos como en  OSX,  mac, como un detalle importante cambiar la versión a la que apunta el script, en mi caso lo tengo para la 2.11.2. Otro detalle importante, Scala usa la VM de java con lo que antes de hacer la instalación o de intentar invocar la consola de Scala asegúrate haber instalado java antes.
Algunos consejos antes de ponernos al tema:

Una herramienta de construcción estrictamente necesaria para trabajar con Scala es  sbt, tiene su propia consola  y a partir de ella como toda herramienta de construcción permite compilar código, esta además nos permite seleccionar los proyectos disponibles y sobre ellos ejecutar testsuites o algún test unitario en particular. Es definitivamente una herramienta muy útil y a la que con toda seguridad dedicaremos tiempo en un futuro. Si quieres comenzar a mirar te animo a ir a al site de esta consola y descargártela.

Respecto a los editores/ides a usar, en mi caso trabajo siempre desde la consola incluso en momentos de estructurar proyecto, a la hora de codificar uso Sublime Text pero para proyectos de determinada envergadura reconozco que Eclipse o IntelliJ serán de mayor utilidad .Otra opción para los amantes de la nube puede ser este ide que uso con bastante frecuencia y en el que al menos un workspace es gratis(http://c9.io) , es uno de los mejores ides que he visto en la nube, tiene además un repositorio git y un linux,ubuntu embebido. Podemos compilar ,ejecutar y todo lo normal que hacemos con un ide de desarrollo,unido a las ventajas de la nube en cuanto a poder trabajar desde cualquier estación de trabajo.
Creo que tras esta breve introducción podemos comenzar. Nuestro objetivo de hoy es explicar toda o casi toda la sintaxis de Scala en el modo mas breve posible de modo que alguien que venga del mundo Java pueda entender casi todo prácticamente al vuelo.


Definiendo una función del modo más simple en Scala , esto es lo equivalente a una función en java. El mismo tipo de definición seria para lo equivalente a un método en java(void)  pero sin retornar valor:

1
2
3
4
5
6
7
// definimos una funcion basica 
// x,y son parametros de entrada de tipo Int
// la función devuelve un valor tambien de tipo Int 

def max(x: Int, y: Int): Int = {
           if (x > y) x 
           else y }

La anterior estructura es la estructura básica de cualquier función con la palabra reservada def.

Es importante tener en cuenta que al ser programación funcional da muchas cosas por asumidas y deja su solución a la JVM

Vamos a poner un ejemplo bastante simple pero que puede ser resuelto de diferentes maneras :
Tenemos un array de String,con 3 elementos y simplemente vamos a imprimir los elementos en la consola:

1
2
3
4
//definimos el array y lo inicializamos 
val args = Array("uno","dos","tres")
args.foreach(arg=>println(arg))
args.foreach(println) 

En la linea 3 imprimimos el contenido del array ,en tan solo una linea.Con foreach recorremos todos los elementos de la coleccion y arg=>println(arg) es una función que toma un parámetro y retorna como resultado algo que hace con dicho parámetro(println(arg)).Este operador (=>)  podríamos decir que es una syntactic sugar termino bastante empleado en inglés y que indica que es una sintaxis usada para hacer las cosas más simples de leer o de explicar.Como por ejemplo cuando queremos indicar algo de un modo bien claro y sin que para ello demos una explicación tan sofisticada.
En el caso de la linea 4 simplemente imprimimos todos los elementos del array ,sin poder interactuar con ellos.

(=>) tal y como indicamos anteriormente este es uno de nuestros principales operadores en Scala con lo cual es para nosotros realmente importante dejar resumida toda su funcionalidad.


1
val f: Function1[Int,String] = myInt => "mi valor int: "+myInt.toString

Tenemos aquí una función que recibe un entero (Int) y retorna el string "mi valor int": + valor entrado de parámetro.Lo anterior es una definición de función hecha desde consola.

1
val f1: Int => String = myInt => "mi otro valor int: "+myInt.toString

La funcionalidad y el resultado tanto de f  como de f1 es la misma.Miremos en que se traduce la función f1, tenemos una función f1 que recibe un entero (Int) y devuelve un String , con el valor recibido como parámetro,myInt,voy a (=>)  hacer lo que tenga que hacer y que en mi caso se trata de imprimir una cadena de texto con el valor del entero.

1
2
3
4
() => Unit
val f : () => Unit  = () => println("Hola Mundo") 
val f : () => Unit  = () => {//cualquier operacion en la misma linea separadas por ;}  
val f : () => Unit  = () => {//cualquier operación en diferentes lineas no es necesario(;) }  

Funciones que ni reciben parámetros y tampoco retornan valor alguno,estaríamos en  presencia de una típica void de java,por el hecho de que no retorna valores.

Un equivalente cuyo resultado sería el mismo que el del resto del grupo anterior es la línea de código que sigue:

1
val f2: function0[Unit] = () => println("cualquier valor ")

Veamos otra utilidad de este fantástico operador:

1
List(1,2,3).map { (x: Int) => x * 2 } 

Tenemos una lista y queremos multiplicar todos sus elementos * 2.Eso es lo que hace nuestra anterior linea de código.Olvidemos por el momento la funcionalidad map,que no es complicada y que esta en la api de Scala sin problema alguno para ser entendida.
La parte de la línea de codigo : (x:Int) => x*2 indica que vamos a coger cada entero Int que se nos pase como parámetro y lo multiplicaremos por 2.
Más adelante continuaremos con nuestro operador (=>) de momento creo será suficiente para lo que explicaremos en las siguientes lecciones.

(_) underscore : es este otro de nuestros operadores de gran importancia y que tiene en Scala una infinidad de utilidades que a continuación iremos explicando:

1
2
3
4
5
6
7
val miArgumento = "salt"
        firstArg match {
          case "salt" => println("pepper")
          case "chips" => println("salsa")
          case "eggs" => println("bacon")
          case _ => println("huh?")
}

En el caso anterior,la linea 6  es la que se ejecuta por defecto,dado que no se cumplan las condiciones anteriores.
También lo usamos en los imports en lo que podría ser el  * en el caso de los imports en java:

1
2
 import scala.util.control.Breaks._
 import java.io._

Aunque quizá su uso mas importante es como placeholder.Vamos a introducir el siguiente ejemplo para ver de un modo mas evidente su funcionalidad:

1
(x: Int) => x > 0

Si aplicamos lo que vimos en la explicación anterior referente al operador  => lo que indica la linea 1 es que dicha función recibe un Int y devuelve un boleano que será true cuando el parámetro de entrada sea > 0.Supongamos que tenemos la siguiente lista de valores:


1
val valores = List(-21, -11, -3, 0, 15, 20)

Hemos de tener en cuenta un detalle importante : internamente cuando creamos una lista (List) o un array(Array) realmente invocamos al siguiente método Array.apply ,para los que venimos del mundo java podríamos hablar de este método como un método estático en java (salvando las distancias, puesto que en scala no tenemos variables ni métodos estáticos).Tenemos a continuación un ejemplo sobre la creación de un lista.

1
2
//ejemplo de código con apply
val valores1 = List.apply(-21, -11, -3, 0, 15, 20)

Como podemos apreciar ,es mucho más simple el modo de creación de una colección inicializada tal y como aparece en la la creación de la lista sin invocar directamente al apply (tener en cuenta que internamente siempre invocará a este método).

Más adelante trataremos las colecciones, de momento solo necesitamos saber que List tiene un método para filtrar los elementos de una lista(filter),con lo que si quisiéramos filtrar los elementos de dicha lista y dejar en ella solo aquellos elementos > 0 la sintaxis seria la siguiente:

1
valores.filter((x: Int) => x > 0)

La anterior linea de código filtra todos los elementos de la lista y deja en la misma los > 0.Referente a la condición de filtrado ver la explicación realizada en lineas anteriores.
Todo lo anterior va muy bien ,pero suponiendo que sabemos el tipo de elemento que contiene la lista y que además vamos a coger todo lo que haya en la lista y comprobar si es  > 0 ,veamos entonces como queda nuestra linea de código:

1
valores.filter(_>0)

Otro ejemplo podría ser una función que recibe dos parámetros de determinado tipo tal y como indica la siguiente linea de código:

1
val f = (_: Int) + (_: Int)

La función anterior sumará 2 enteros y es una solución a lo que seria _ + _ , solución que nos devolvería un error debido a una ambigüedad en los parámetros.
Existen muchos casos en los que usaríamos el underscore(_) como un placeholder. He aquí otro de los ejemplos en la siguiente linea:

1
2
valores.foreach(println _)
valores.foreach(arg => println(arg))

Ambas soluciones son válidas ,me inclino por la linea 1 que es un tanto mas compacta y además sigue siendo intuitiva.Recordemos que si queremos imprimir solo contenidos es suficiente con la siguiente linea:

1
valores.foreach(println)

Explicaremos un último uso del (_) como placeholder

1
2
3
4
5
6
7
8
//creamos una funcion suma 
def sum(a: Int, b: Int, c: Int) = a + b + c
//asigno dicha funcion a un valor ,no necesito declarar 
//las variables ,dado que hemos puesto _ como placeholder 
//asumirá que conoce el resto de los parámetros 
val a = sum _
//esta operacion es totalmente posible ,devuelve 11
a(2,4,5)

En la asignación sum _  es necesario el underscore para indicar que tenemos más parámetros ,cuantos? pues los que hayan sido definidos en la funcion sum .Tenemos aquí a algo curioso,con la asignación  tenemos una instancia de una clase interna de scala lo cual permitirá que podamos realizar la siguiente operación a(2,4,5) ó a.apply(2,4,5) en éste último caso estamos llamando a un método que lo que  hara será asignar los parámetros para realizar la llamada a la función.Podríamos decir que con las asignaciones tenemos la instancia de la clase interna de scala con ello el método apply,que a efectos prácticos tampoco estaremos usándolo.

1
val b = sum(1, _: Int, 3)

La anterior asignación es también válida.Vemos aquí otra utilidad en la que el underscore actua como placeholder y ejecutará la función solamente llamando a un parámetro ejemplo : b.apply(4) ó b(4) ,ambos declaraciones son validas.
Por último en esta entrega tenemos las Clousures , que son ?Conceptualmente son funciones que contienen lo que llamamos variables libres,variables que no dependen de ningún parámetro pasado a la función.Son variables cerradas(closed ) o lo que es lo mismo no son variables visibles en el momento de crear la función.Lo mejor es a través de ejemplos:

1
(x: Int) => x + variable_libre

En el anterior código variable_libre  no depende de ningún parámetro de entrada y en este caso generará un error ya que la misma no ha sido declarada.En el siguiente ejemplo vemos lo que son las variables libres anteriormente explicadas.

1
2
3
4
var variable_libre = 10
val addVariable_libre = (x: Int) => x + variable_libre
addVariable_libre(20)
res3: Int = 30

El valor de la función addVariable_libre creado en runtime es llamado Clousure(función objeto que contiene variables libres,que no se ven en el momento de ser creada dicha función).Un detalle,variable_libre podría cambiar su valor y aún así el valor de la función se actualizaría para las nuevas operatorias. Esto último lo soluciona internamente Scala sin que tengamos que preocuparnos de ello.
El siguiente ejemplo muestra un array al que le pasaremos una función que es una clousure ya que contiene una variable libre (que no se pasa como  parámetro):

1
2
3
var sumatoria = 0
val aArray = Array(-3,5,7,9)
aArray.foreach(sumatoria +=  _)

La variable sumatoria es una variable libre que usa underscore (_) como placeholder y sumará cada uno de los elementos del array aArray.Un detalle que por simple no deja de ser extremadamente importante es el uso de var y de val; el primero declara un valor que puede ser modificado mientras que el último,val,declara un valor fijo.Si en el código anterior sustituimos la linea 1 por la declaración de val sumatoria = 0,el código generaría error ya que en ese caso dicha variable no podría ser modificada.


Hemos visto los siguientes operadores : _ ; => y las clousures. Algunos de los ejemplos contienen teoría que aún no hemos visto, pero de momento la idea es centrarse en los anteriores operadores y sus diferentes usos.
Bueno "people" hasta otra entrega les deseo buena suerte y mientras espero vayan avanzando en Scala,sin perder de vista nuestro objetivo final que será analizar una aplicación programada con Scala.