Diapositivas de una presentación que di para la Scala Meetup Montevideo el 21 de marzo de 2013, para compartir la experiencia de uso de Scala como parte de mi trabajo en proyectos de vinculación entre ANCAP y la Universidad de la República.
Resistencia extrema al cobre por un consorcio bacteriano conformado por Sulfo...
Scala en proyectos de vinculación Ancap-UR - 2013-03
1. Experience report 2009 - 2013
Scala en proyectos de
vinculación ANCAP-UR
Germán Ferrari
Marzo 2013
@gerferra
uy.linkedin.com/in/gerferra/
2. Proyectos
2009 - 2010
"Modelo estocástico
múltiple-etapa para apoyo
a la toma de decisiones
en la planificación de la
producción"
2012 - 2013
Extensión al proyecto
original. En curso
3. Equipo
Ing. Quim. Bernardo Zimberg - ANCAP
M.Sc. Carlos Testuri - FIng, UR
Ing. Comp. Germán Ferrari - FIng, UR
4. Componentes
Modelo matemático
Escrito en Mathprog
Resuelto con herramientas de GLPK
Aplicación de escritorio
Inicialmente: Entrada de datos
Con el tiempo
Ejecución y monitoreo del solver
Reporte de resultados
Scala
5. Por qué Scala?
Único programando, fascinado con el lenguaje
Java era una alternativa viable
Scala es "sólo una biblioteca"
6. Por qué Scala?
Tipado estático
Favorece
inmutabilidad
Código legible y corto
Inferencia de tipos
Sin boilerplate
DSL friendly
Biblioteca estándar
Colecciones
Procesos
Parsers
REPL
Comunidad
Fácil! para programadores Java ;)
7. Herramientas y bibliotecas usadas
Scala-Swing
spray-json
Scala IO
ScalaTest
scala.sys.process
PackratParsers
sbt, sbt-assembly, sbteclipse
Scala IDE for Eclipse
8. Scala-Swing
Wrapper sobre Swing
Se integra naturalmente en Scala
Feel declarativo
API más simple
Usando MVP inspirado en el propuesto en
GWT
No muy Scala-like pero funciona
9. Scala-Swing - ejemplos
object HelloWorld extends SimpleSwingApplication {
def top = new MainFrame {
title = "Hello, World!"
contents = new Button {
text = "Click Me!"
}
}
}
10. Scala-Swing - ejemplos
val b = new Button {
text = "OK"
font = f
preferredSize = (20, 20)
}
listenTo(b)
reactions += {
case ButtonClicked(`b`) => //reaction here
}
11. Scala-Swing - ejemplos
new FlowPanel {
contents ++= new Button("a") :: new Button("b") :: Nil
}
new BoxPanel(Horizontal) {
contents ++= new Label("text") :: HStrut(2) ::
new Button("a") :: HGlue :: new Button("b") :: Nil
}
new BorderPanel {
layout(new Button("North")) = Position.North
layout(new Button("Center")) = Position.Center
}
12. Scala-Swing - a tener en cuenta
No es wrapper 100% completo
No está mantenido activamente
Relativamente fácil de extender
ScalaSwingContrib
Bastante fácil de usar pero falta documentación
(Java)Swing usa reflection para algunas cosas
ScalaFX
13. (De)Serialización de JSON basado en Type-
classes
trait JsonReader[T] { def read(json: JsValue): T }
trait JsonWriter[T] { def write(obj: T): JsValue }
trait JsonFormat[T] extends
JsonReader[T] with JsonWriter[T]
Usado para persistir configuración y archivos
de proyectos
spray-json
14. spray-json - ejemplos
case class Color(name: String, red: Int, green: Int,
blue: Int)
object MyJsonProtocol extends DefaultJsonProtocol {
implicit val colorFormat: JsonFormat[Color] =
jsonFormat4(Color)
}
import MyJsonProtocol.colorFormat
val json = Color("CadetBlue", 95, 158, 160).toJson
val color = json.convertTo[Color]
16. spray-json - ejemplos
type RetRels = Seq[(Ship, Ship)]
implicit val RetRelsWriter = new RootJsonWriter[RetRels] {
def write(rels: RetRels) =
rels.map { case (s1, s2) => s1.name -> s2.name }.toJson
}
implicit val RetRelsReader = new RootJsonReader[Seq[Ship] => RetRels] {
def read(value: JsValue) = { imps =>
val ship = imps.map { s => s.name -> s }.toMap
value.convertTo[Seq[(String, String)]] map {
case (n1, n2) => ship(n1) -> ship(n2)
}
}
}
val retRels = json.convertTo[Seq[Ship] => RetRels].apply(imps)
17. spray-json - resumen
Lógica de conversión desacoplada
Gran control sobre la conversión
Múltiples implementaciones
Distintos niveles de refinamiento
Conversiones asimétricas
Escalable
Agregar nuevas conversiones es barato
Las conversiones se pueden combinar
18. Scala IO
Entrada / salida en Scala
Manejo simple, portable, correcto y eficiente de
archivos y otros recursos de E/S
Componentes
IO Básico
Archivos
Acceso asincrónico
Processor
19. Scala IO - ejemplos
import scalax.file.Path
val path = Path("file")
path.byteArray // lee todos los bytes en memoria
// `bytes` es lazy y no lee los bytes hasta que son
// requeridos o forzados
path.bytes.drop(5).take(5).force
// lee todos los bytes en un String. El Codec puede ser
// implícito
path.string(Codec.UTF8)
21. Scala IO - ejemplos
def command: (String, URL) = {
val name = if (isWin) "cmd.exe" else "cmd"
name -> this.getClass.getResource(name)
}
val basePath: Path = ...
val (cmdName, cmdResource) = command
val cmdPath = basePath / "cmd" / cmdName
Resource.fromURL(cmdResource).copyDataTo(cmdPath)
cmdPath.attributes = Seq(ExecuteAccessAttribute(true))
22. Scala IO - ejemplos
import scalax.io._
val output:Output = Resource.fromOutputStream(
new java.io.FileOutputStream("daily-scala.out"))
val in:Input = Resource.fromFile("daily-scala.out")
for{
processor <- output.outputProcessor
out = processor.asOutput
}{
// todas las escrituras van a ir al mismo output stream/channel abierto
out.write("first writen")
out.write("second write")
}
// muestra las líneas escritas
in.string
24. ScalaTest - ejemplos
import org.junit.runner.RunWith
import org.scalatest.junit.JUnitRunner
@RunWith(classOf[JUnitRunner])
class DummyTest extends FlatSpec with ShouldMatchers {
"A Stack" should "pop values in last-in-first-out order" in {
val stack = new Stack[Int]
stack.push(1)
stack.push(2)
stack.pop() should equal (2)
stack.pop() should equal (1)
}
it should "throw NoSuchElementException if an empty stack is popped" in {
val emptyStack = new Stack[String]
evaluating { emptyStack.pop() } should produce [NoSuchElementException]
}}
25. scala.sys.process
API para ejecutar y controlar procesos
Indicar qué correr y cómo
Manejar E/S
Correr proceso
Utilizado para ejecución y monitoreo del solver
26. scala.sys.process - ejemplos
import scala.sys.process._
// Ejecuta "ls" y envía la salida a stdout
"ls".!
// Ejecuta "ls" y devuelve `Stream[String]` con la salida.
val contents = Process("ls").lines
// Ejecuta "ls" y devuelve un String con la salida.
def contentsOf(dir: String): String = Seq("ls", dir).!!
28. scala.sys.process - ejemplos
val builder = Process(glpsol.cmd,
Seq(
"--model", modelPath.path,
"--data", dataPath.path,
"--check"))
val logger = ProcessLogger { line =>
onEDT { view.append(line) }
}
val proc = builder.run(logger)
29. PackratParsers
Construcción de parsers dentro del lenguaje
Admiten gramaticas recursivas por la izquierda
Los parsers comunes entran en loop
Experimentos muy básicos de parsear
entidades Mathprog
30. PackratParsers - ejemplos
expr ::= term { "+" term | "-" term }
term ::= factor { "*" factor | "/" factor }
factor ::= floatingPointNumber | "(" expr ")".
import scala.util.parsing.combinator._
class Arith extends JavaTokenParsers with PackratParsers {
lazy val expr: PackratParser[Any] = term ~ rep("+" ~ term | "-" ~ term)
lazy val term: PackratParser[Any] = factor ~ rep("*" ~ factor | "/" ~ factor)
lazy val factor: PackratParser[Any] = floatingPointNumber | "(" ~ expr ~ ")"
}
31. PackratParsers - ejemplos
sealed trait Expr
case class Add(t1: Expr, t2: Expr) extends Expr
case class Sub(t1: Expr, t2: Expr) extends Expr
sealed trait Term extends Expr
case class Mul(f1: Expr, f2: Expr) extends Term
case class Div(f1: Expr, f2: Expr) extends Term
sealed trait Factor extends Term
case class Num(n: Float) extends Factor
32. PackratParsers - ejemplos
class Arith extends JavaTokenParsers with PackratParsers {
lazy val expr: PackratParser[Expr] =
term ~ rep("+" ~ term | "-" ~ term) ^^ {
case term ~ list => ???
}
lazy val term: PackratParser[Expr] =
factor ~ rep("*" ~ factor | "/" ~ factor) ^^ {
case factor ~ list => ???
}
lazy val factor: PackratParser[Expr] = (
floatingPointNumber ^^ { ??? }
| "(" ~ expr ~ ")" ^^ { ??? } )
}
44. sbt-assembly
import AssemblyKeys._
assemblySettings
// ... buil.sbt mostrado antes ...
mainClass in assembly := Some("uy.edu.fing.inco.invop.ancap.sega.ui.Sega")
packageOptions in assembly +=
Package.ManifestAttributes("SplashScreen-Image" ->
"uy/edu/fing/inco/invop/ancap/sega/splash.png")
45. Scala IDE for Eclipse
Plugin para desarrollo con Scala en Eclipse
Update site Eclipse Indigo y Scala 2.10
http://download.scala-ide.org/sdk/e37/scala210/stable/site
46. Lo peor
El compilador es lento
Las herramientas de desarrollo consumen
mucha memoria
47. Lo mejor
Se puede empezar "pequeño" y crecer a
demanda
Scala es escalable => nuestras aplicaciones
son escalables
Se puede tener tipado estático y escribir poco
al mismo tiempo :)