33
SCALA ДЛЯ ДЖЕДАЕВ Владимир Парфиненко vladimir.parﬁ[email protected] @cypok

description

Второе выступление в рамках спецкурса "Немейнстримовые технологии разработки", читаемого в НГУ. http://bit.ly/mainstreamless Аудио дорожка работает, но нужно иметь некоторое терпение, так как грузится она не моментально.

### Transcript of Scala for Jedi

THE LIGHT SIDE

THE DARK SIDE

TYPES

OPTION

val set = Set(42, null, "Yoda")val found = set find { _ == null }

if (found != null) { // huh, we've found it or not? println(s"Found \$found!")} else { println("Not found.")}

OPTION

val set = Set(42, null, "Yoda")val found = set find { _ == null }

found match { case Some(elem) => println(s"Found \$elem!") case None => println("Not found.")}

string interpolation 2.10

TYPES ON STEROIDS

sealed abstract class Option[+A] { def get: A}

final case class Some[+A](x: A) extends Option[A] { def get = x}

case object None extends Option[Nothing] { def get = throw new NoSuchElementException("None.get")}

TYPE COVARIANCE

not implemented2.10

class Cell[T](x: T) { def get: T = ??? def set(x: T) { ??? }} val c1 = new Cell[String]("Anakin")

val c2: Cell[Any] = c1 // type mismatch

TYPE COVARIANCE

class Cell[+T](x: T) { def get: T = ???} val c1 = new Cell[String]("Anakin")

val c2: Cell[Any] = c1val jedi = c2.get

TYPE COVARIANCE

class Cell[+T](x: T) { def get: T = ??? def set(x: T) { ??? } // compilation error} val c1 = new Cell[String]("Anakin")

val c2: Cell[Any] = c1c2.set(37)

TYPE COVARIANCE

class Cell[-T](x: T) { def get: T = ??? // compilation error def set(x: T) { ??? }} val c1 = new Cell[Any](37)

val c2: Cell[String] = c1val jedi = c2.get

TYPE COVARIANCE

class Cell[-T](x: T) { def set(x: T) { ??? }} val c1 = new Cell[Any]('Anakin)

val c2: Cell[String] = c1c2.set("Darth Vader")

LOWER & UPPER BOUNDS

class List[+A] { def ++[B >: A](that: List[B]): List[B] = ???}

val strs = List("Leia", "Organa")val syms = List('Anakin, 'Skywalker)val all = strs ++ syms // List[java.io.Serializable]

def max[A <: Ordered[_]](xs: List[A]): A = ???val accounts: List[Money]max(accounts)

CONTEXT BOUNDStrait Jedi { def force: Double }

val jediOrder: Set[Jedi]val grandMaster = jediOrder.max // No implicit Ordering defined for Jedi.

implicit val jediOrdering = new Ordering[Jedi] { def compare(j1: Jedi, j2: Jedi) = j1.force.compare(j2.force)}

val grandMaster = jediOrder.max

trait TraversableOnce[+A] { def max[B >: A](implicit cmp: Ordering[B]): A = ??? def max[A : Ordering]: A = ???}

TYPES HIERARCHY Any

AnyRef/Object

ScalaObject

Java classesScala classes

Null

Nothing

AnyVal

PrimitivesValue classes2.10

TYPES ON STEROIDS

sealed abstract class Option[+A] { def get: A}

final case class Some[+A](x: A) extends Option[A] { def get = x}

case object None extends Option[Nothing] { def get = throw new NoSuchElementException("None.get")}

PARALLELISM & CONCURRENCY

PARALLEL COLLECTIONSval nums = (1 to 10).parnums foreach { x => print(x + " ") } // 1 2 8 9 10 7 5 6 3 4

nums reduce { _ - _ } // -15

nums reduce { _ - _ } // 5

nums reduce { _ + _ } // 55

val word = Seq("G", "r", "i", "e", "v", "o", "u", "s")word.par reduce { _ ++ _ } // Grievous

FUTURES 2.10

• Хранилище для значения, которое будет получено в будущем

• Получение значения может быть выполнено асинхронно и не блокировать программу

• Значение может быть не получено вовсе

FUTURESval f: Future[List[String]] = future { session.getRecentPosts}

f onSuccess { case posts => for (post <- posts) println(post)}

f onFailure { case t => println("An error has occured: " + t.getMessage)}

FOR

val files: Seq[File]

for (file <- files) { println(file.getName)}

FOR

def fileLines(f: File): Seq[String] = ???

for (file <- files) { if (!file.getName.startsWith(".")) { for (line <- fileLines(file)) { if (line.nonEmpty) { println(file + ": " + line) } } }}

FOR

for { file <- files if !file.getName.startsWith(".") line <- fileLines(file) if line.nonEmpty} println(file + ": " + line)

files withFilter { !_.getName.startsWith(".") } foreach { file => fileLines withFilter { _.nonEmpty } foreach { line => println(file + ": " + line) }}

FOR

val lines = for { file <- files if !file.getName.startsWith(".") line <- fileLines(file) if line.nonEmpty} yield (file + ": " + line)

files withFilter { !_.getName.startsWith(".") } flatMap { file => fileLines(file) withFilter { _.nonEmpty } map { line => file + ": " + line }}

FUTURES

val usdQuote = future { connection.getCurrentValue(USD) }val chfQuote = future { connection.getCurrentValue(CHF) }

val purchase = for { usd <- usdQuote chf <- chfQuote if isProfitable(usd, chf)} yield connection.buy(amount, chf)

purchase onSuccess { case _ => println(s"Purchased \$amount CHF")}

FUTURESval rateQuote = future { connection.getCurrentValue(USD)}

val purchase = rateQuote map { quote => if (isProfitable(quote)) connection.buy(amount, quote) else throw new Exception("not profitable")}

purchase onSuccess { case _ => println(s"Purchased \$amount USD")}

filter, fallbackTo, recoverWith, andThen, …

PROMISESval p = promise[T]val f = p.future

val producer = future { val r = produceSomething() p success r continueDoingSomethingUnrelated()}

val consumer = future { startDoingSomething() f onSuccess { case r => doSomethingWithResult() }}

PROMISES

def first[T](f: Future[T], g: Future[T]): Future[T] = { val p = promise[T]

f onSuccess { case x => p.tryComplete(x) }

g onSuccess { case x => p.tryComplete(x) }

p.future}

ACTORS & AKKA 2.10

• Акторы – это приватные данные и описание поведения

•Общение между акторами только через сообщения с неизменяемыми данными

• Акторы могут создавать других акторов и управлять ими в случае исключительных ситуаций

ACTORS

class MyActor extends Actor { def receive = { case "test" => log("received test") case _ => log("received unknown message") }}

object Main extends App { val system = ActorSystem("MySystem") val myActor = system.actorOf(Props[MyActor], name = "myactor") myActor ! "test"}

ACTORSclass Squarer extends Actor { def receive = { case x: Int => sender ! (x * x) case x: Double => sender ! (x * x) }}

class Mathematician extends Actor { val squarer = context.actorOf(Props[Squarer], name = "squarer") def receive = { case x: Int => (squarer ? x) onComplete { case Success(x) => log(x) case Failure => fail() } }}

OTHER FEATURES

@tailrec

def find[A](xs

: List[A], p:

(A => Boolean)

): Option[A] =

{

xs match {

case Nil =

> None

:: tail =>

if (p(he

) else find(ta

il, p)

}}

trait Provider { def smth: Int}

class LazyOne extends Provider { lazy val smth = { ??? }}

assert(assertion: Boolean, message: => Any): Unit

assert(true, { ??? })assert(false, { ??? })

implicit class RockString(str: String) { def rock() = ???}"foo".rock()

2.10packa

ge my

class Foo

{

private[

this] val

x: Int = ?

??

private[

Foo] val y

: Int = ??

?

private[

my] val z:

Int = ???

}

val xml = <and><much>More!</much></and>