SyntaxHighlighter

martes, 2 de junio de 2015

Scala with Style

Acabo de verme un video Martin Odersky, creador  de scala, sobre guias de estilo en este lenguaje funcional. El video esta muy bien, agradable y clara exposicion.

https://www.youtube.com/watch?v=kkTFx3-duc8

Resumen para no gastar una hora viendo el video y para que a mi no se me olvide :)

Choice #1:Infix vs .
items + 10 or item.(10)
xs map f or xs.map(f)
xs flatMap fun filterNot isZero groupBy keyfn or  xs.flatMap(fun).filterNot(isZero).groupBy(keyfn)

conclusion: donde haya duda sobre cual es el objecto y cual es el verbo es mejor . (el de la derecha)
Lo que me sugiere que si pensamos en sujetos y verbos seguimos pensando en objecto....no sera facil salir de esa forma de pensar.

Choice #2:Alphabetic vs Symbolic

xs map f or xs *|> f
vector + f or vector.add(f)
(xs.foldLeft(z))(op) or (z /: xs)(op)
UNDEFINED   or  ???

Odersky recomienda los de la izquierda excepto por el foldLeft donde admite que a el le gusta y le parece mas claro el de la derecha que es como un domino que va de izq a derecha pero admite que la mayor parte de la gente no entiende esta simbologia y que por lo mismo quiza no sea la mejor solucion.


Choice #3:Loop, recursion  or combinations?

xs map f
or
var buf  = new ListBuffer[String]
for (x <- xs) buf += f(x)
xs.toList
or
def recurs(xs: List[String]) = xs match {
   case  x :: xs1  => f(x) :: recur(xs1)
   case Nil  => Nil
}

No comment....

xs.grouped(2).toList.map {
   case List(x,y) = > x*y
}

or

var  buf = new ListBuffer[Int]
var ys = xs
while (ys.nonEmpty){
   guf += ys(0)*ys(1)
   ys = ys.tail.tail
}

or

def recur(xs: List[Int]): List[Int] = xs match {
   case x1 :: x2 :: xs1 => (x1 * x2) :: recur(xs1)
   case Nil => Nil
}
recur(xs)

Combinators: Easiest to use
Recursive functions: bedrock of FP
Pattern matching: Much clearer and safer than test and selections
Loops: Because they are familiar, and sometimes are the simples solution

Recomendations:
1. Consider using combinators first
2. if this becomes too tedious, or efficiency is a big concern, fall back on tail-recursive functions.
3. Loops can be use in simple cases, or when the computation inherently modifies state.

Choice #4: Procedures or "="

def swap[T](arr: Array[T], i: Int, j: Int){
  val t = arr(i);ar(i) = arr(j);arr(j) = t
}
def swap[T](arr: Array[T], i:Int, j:Int): Unit = {
   val t = arr(i);arr(i) = arr(j); arr(j) = t
}


Scala accident ??

Choice #5: Private vs nested

def outer(owner: Symbol) = {
   def  isJava(sym: symbol): Boolean = sym hasFlag JAVA
   if (symbols exists isJava)
}

easy nested almost always you can avoid passing parameters from the enviroment. But if you not capturing nothing code is harder to read.

def  isJava(sym: symbol): Boolean = sym hasFlag JAVA

def outer(owner: Symbol) = {
   if (symbols exists isJava)
}


Choice #6: Pattern matching vs dynamic dispatch

class Shape
  def area: Double
case class Circle(centre: Point, radius: Double) extends Shape
  def area = pi * radius * radius
case class Rectangle(ll: Point, ur: Point)
  def area = (ur.x - ll.x)* (ur.y - ll.y)

or

def area(s: Shape): Double = s match {
  case Circle(_, r) => math.pi*r*r
  case Rectangle(ll,ur) => (ur.x - ll.x)* (ur.y - ll.y)
...
}

Un espectador pregunta: Y que pasa cuando uno se olvida de definir el metodo para uno de las clases?
Hay algo que se llama sealed classes