Scala
для

Java программистов

Павел Павлов
О себе
Занимаюсь системным программированием
● компиляторы, среды исполнения
● Excelsior JET - JVM with AOT compiler
● код на орбите (ГЛОНАСС)
Преподаю
● научное руководство студентами (НГУ)
● подготовка юниоров в компании
Участник Scala community
● Scala core committer (stdlib, compiler)
● Организовал ScalaNsk
Одна история из
реальной жизни
Excelsior JET
● Полная реализация Java SE
○ первый релиз - 2000 год
○ с 2005 сертифицирована как Java Compatible

● AOT Compiler + Java Runtime
○ смешанная компиляция: AOT + JIT
○ поддержка нестандартных загрузчиков классов в
AOT режиме (для Eclipse RCP, Tomcat)

● Toolkit
○ Deployment
○ Startup Optimizer
Excelsior JET
● Одна из 4х Java SE VM, сделанных с нуля
○
○
○
○

Sun/Oracle HotSpot
JRockit
IBM J9
Excelsior JET

● Было: очень древний codebase
○ заложен в конце 80х/начале 90х
○ код морально устарел
○ изменилось всё: требования, технологии,
инструменты, процессы
○ куда податься?
Требования к языку
● Возможность создавать большие системы
○ и долгоживущие
○ и сложные

● Производительность

● статическая типизация
● развитые инструменты разработки
● промышленное качество
Требования к языку
● Возможность создавать большие системы
○ и долгоживущие
○ и сложные

● Производительность

● Java и/или C++
Требования к языку
● Возможность создавать большие системы
○ и долгоживущие
○ и сложные

● Производительность
● Самоприменимость
● Java
Требования к языку
● Возможность создавать большие системы
○ и долгоживущие
○ и сложные

● Производительность
● Самоприменимость
● Java? А как насчёт:
○
○
○
○

скорости разработки?
объёма кода?
гибкости, мощи средств языка?
в конце концов, количества fun’а?
И тут я наткнулся на Scala
JET на Scala: наш опыт
●
●
●
●

Оптимизирующий компилятор
Новое ядро, implemented from scratch
R&D "по-взрослому"
Команда: ≤5 человек
○ 4 из них не знали Скалу

● Время: 1.5 года * 4 человек
○ всё работает, релиз был в апреле 2013
○ ~40kloc
Что такое Scala?
Язык Scala: характеристика
● компилируемый
● строго статически типизированный
● автоматический вывод типов (type
inference)
● OOP + FP
● "лёгкий" синтаксис
● работает на платформе JVM
● бесшовная интеграция с Java
Язык Scala: цели
● Язык общего назначения
● Альтернатива/замена Java
● Внедрение FP в mainstream
● Преодоление "застоя" в OOP
Целевая аудитория:
1. Java-программисты (народные массы)
Лучший язык, FP

2. Ruby/Python(/JS)-программисты
Статическая типизация, производительность

3. Функциональщики
Использование FP в mainstream
Java
C#

Ruby
Erlang
JavaScript
Python

C

Clojure
Haskell
PHP

C++
Go

Lua
Groovy
Язык Scala: история
Язык Scala: история

Martin Odersky
Язык Scala: история

Martin Odersky

Philip Wadler
Язык Scala: история
Автор: Martin Odersky (EPFL)
1995-2001 Pizza language (Odersky & Wadler)
"better Java": Java + generics, function types &
closures, ADT & pattern matching

1997-1998 Generic Java
generics & javac compiler => Java language

2001-2005 Scala 1.x
"better than Java"

2006Scala 2.x
2009-2010 Проникновение в индустрию
Success story: Twitter
● 2006: начало - всё на Ruby on Rails
● 2007-2008: взрывной рост популярности
Success story: Twitter
● 2006: начало - всё на Ruby on Rails
● 2007-2008: взрывной рост популярности
Решение:

+
Популярность Scala
● 11 место - RedMonk Programming Language
Rankings (StackOverflow, GitHub)
● 36 место - TIOBE index
(поисковые запросы)
http://www.infoq.com/research/next-jvm-language
Инструменты
Hello, REPL!
scala> val repl = Map('R' -> "Read", 'E' -> "Eval",
|

'P' -> "Print", 'L' -> "Loop")

repl: immutable.Map[Char,String] = Map(...)
scala> for ((k, v) <- repl) println(s"$k is for $v")
R is for Read
E is for Eval
P is for Print
L is for Loop
Синтаксис: values & variables
val x: Int = 42
val ys = List(1, 2, 3)

// y: List[Int]

var z = "hello"

// z: String
Синтаксис: values & variables
val x: Int = 42
val ys = List(1, 2, 3)

// y: List[Int]

var z = "hello"

// z: String

make val not var
Синтаксис: functions
val x: Int = 42
val ys = List(1, 2, 3)

// y: List[Int]

var z = "hello"

// z: String

def max(a: Int, b: Int): Int = if (a > b) a else b
def inc(x: Int) = x + 1
val inc = { x: Int => x + 1 }

// inc: Int => Int
Синтаксис: основы
val x: Int = 42
val ys = List(1, 2, 3)

// y: List[Int]

var z = "hello"

// z: String

def max(a: Int, b: Int): Int = if (a > b) a else b
def inc(x: Int) = x + 1
val inc = { x: Int => x + 1 }

// inc: Int => Int

ys map inc

// List(2, 3, 4)

ys map { x => x + 1 }
ys map { _ + 1 }
ys filter { _ % 2 != 0 }

// List(1, 3)

ys reduce max

// max(1, max(2, 3))

ys reduce { (x, y) => x + y }

// 1 + 2 + 3
Классы и объекты
abstract class Animal {
def name: String
}
class Person(firstName: String, lastName: String)
extends Animal {
val name = firstName + " " + lastName
}
class Employee(firstName: String, lastName: String,
val age: Int, var salary: Double)
extends Person(firstName, lastName)
object Main extends App {
val p = new Employee("John", "Doe", 20, 300.0)
println(p.name + " is + p.age + " years old")
}
Traits: множественное наследование
с человеческим лицом
trait Ordered[A] {
def compare(that: A): Int
def <

(that: A): Boolean = (this compare that) <

0

def >

(that: A): Boolean = (this compare that) >

0

def <= (that: A): Boolean = (this compare that) <= 0
def >= (that: A): Boolean = (this compare that) >= 0
}
class Money extends SomeTrait with Ordered[Money] {
def compare(that: Money) = ...
}
Types hierarchy
Operators are methods
List(1, 2, 3).map(inc)

// List(2, 3, 4)

List(1, 2, 3) map inc

// <- операторный синтаксис

abstract class Set[T] {
def contains(x: T): Boolean
def - (x: T): Set[T]
def !@#%^&*-+ : Int

// <- пожалуй, так делать не стоит

}
def foo(s: Set[Int]) {
if (s contains 42) println(s - 42)
}
1 + 3*5

=>

1.+(3.*(5))
Functions are objects
Функциональные типы: (A => B)
trait Function1[A, B] {
def apply(x: A): B
}
val inc = { x: Int => x + 1 }

val inc = new Function1[Int, Int] {
def apply(x: Int): Int = { x + 1 }
}
inc(4)

// inc.apply(4)

// Function1[A, B]
Вызов и индексация
val inverse = { x: Int => 1.0 / x }
inverse(1)

// =>

inverse.apply(1)

val a = Array(0.33, 0.5) // =>

Array.apply(0.33, 0.5)

a(1) /*0.5*/

// =>

a.apply(1)

a(0) = 1.0

// =>

a.update(0, 1.0)

def foo(f: Int => Double) {
println(f(1))

// =>

println(f.apply(1))

}
foo(inverse)

// 1.0

foo(a)

// 0.5

Array[T] is a function (Int => T)!
Pattern matching
val anything: Any = ...
val str = anything match {
case 1

=> "one"

case x: Int if x > 0

=>

"positive integer"

case x: Float if x > 0

=>

"positive float"

case _: String

=>

"string"

case _

=>

"unknown"

}

“switch/case на стероидах”
Алгебраические типы
type List[T] = Nil
| Cons(head: T, tail: List[T])
type Option[T] = None
| Some(value: T)
type Tree[T] = Leaf
| Branch(l, r: Tree[T], value: T)
ADT in action
sealed class Expr
case class Var(name: String) extends Expr
case class Num(value: Int) extends Expr
case class Neg(arg: Expr) extends Expr
case class Add(arg1: Expr, arg2: Expr) extends Expr
def optimize(expr: Expr): Expr = expr match {
case Neg(Neg(x))

=> optimize(x)

case Add(x, Num(0))

=> optimize(x)

case Neg(Num(x))

=> Num(-x)

case Add(x, Neg(y)) if x == y => Num(0)
case Add(Num(x), Num(y))
case Neg(x)

=> Neg(optimize(x))

case Add(x, y)

=> Add(optimize(x), optimize(y))

case _
}

=> Num(x + y)

=> expr
Pattern matching: extractors
object PowerOfTwo {
import java.lang.Long.{numberOfLeadingZeros => nlz}
def apply(i: Int): Long = 1L << i
def unapply(x: Long): Option[Int] =
if (((x & (x-1)) == 0) && (x > 0))
Some(63 - nlz(x)) else None
}
def optimize(e: Expr) = e match {
case Mul(x, PowerOfTwo(n)) => Shl(x, n)
case Div(x, PowerOfTwo(n)) => Shr(x, n)
case Rem(x, PowerOfTwo(n)) => And(x, PowerOfTwo(n) - 1)
}
Коллекции & итерация
Коллекции - первая по важности вещь после
собственно языковых фич
● Они вездесущи
● Дизайн стандартной библиотеки коллекций
влияет на каждую программу, причём в
значительной степени
● Они формируют словарь, с помощью
которого программист выражает свои
мысли
Scala Collections
Scala Collections: API
● functional-style
● collect, count, exists, filter, find, flatMap, fold, forall,
●

foreach, groupBy, map, max/min, partition, reduce,
splitAt, take, to, ...
примеры:
val people: Seq[Person] = ...
val (minors, adults) = people partition (_.age < 18)

● параллельные коллекции: .par, tuning (thread pools
etc.)
for comprehension
● обобщённый цикл for
○ с поддержкой фильтров и pattern matching

●
●
●
●

преобразователь потоков данных
язык запросов
монадический комбинатор
всего лишь синтаксический сахар
for loop: basic form
val files: Seq[File] = ...
for (file <- files) {
println(file.getName)
}
files foreach { file =>
println(file.getName)
}
val names = for (file <- files) yield file.getName
val names = files map { _.getName }
for loop: filters & nested loops
def content(f: File): Seq[String] = ???
for {
file <- files
if !file.getName.startsWith(".")
line <- content(file)
if line.nonEmpty
} println(file + ": " + line)
files withFilter (!_.getName.startsWith(".")) foreach { file =>
content(file) withFilter (_.nonEmpty) foreach { line =>
println(file + ": " + line)
}
}
for loop: filters & nested loops
def content(f: File): Seq[String] = ???
val lines = for {
file <- files
if !file.getName.startsWith(".")
line <- content(file)
if line.nonEmpty
} yield file + ": " + line
files withFilter (!_.getName.startsWith(".")) flatMap { file =>
content(file) withFilter (_.nonEmpty) map { line =>
file + ": " + line
}
}
Implicits
●
●
●
●

Extension methods
Automatic adaptors
DSLs
Typeclass pattern (C++ concepts)
Internal DSLs
Строковые интерполяторы
val name = "John"
s"Hello, $name" // то же, что "Hello, " + name
println(f"$companyName%15s")
val a: Int = b"100011"
sql"select * from user where id = $id"
Строковые интерполяторы
Простейший html-интерполятор для Play:
val link = "http://example.com"
val userName = "Joe"
val content = html"""
<img src="user.png"/> $userName"""
val result = html"""
<a href="$link">$content</a>"""
Строковые интерполяторы
Простейший html-интерполятор для Play:
implicit class HtmlInterpolatorHelper(val sc: StringContext) extends AnyVal {
def html(args: Any*): Html = {
val strings = sc.parts.iterator
val expressions = args.iterator
val buffer = new StringBuilder(strings.next())
while(strings.hasNext) {
val nextExpr = expressions.next()
nextExpr match {
case html: Html => buffer.append(html.toString)
case other => buffer.append(HtmlFormat.escape(other.toString))
}
buffer.append(strings.next())
}
new Html(buffer)
}
}
Parallelism & concurrency
val people: Seq[Person] = ...
val (minors, adults) = people partition (_.age < 18)
Parallelism & concurrency
val people: Seq[Person] = ...
val (minors, adults) = people.par partition (_.age < 18)
Parallelism & concurrency
val people: Seq[Person] = ...
val (minors, adults) = people.par partition (_.age < 18)
actor {
receive {
case people: Seq[Person] =>
val (minors, adults) = people partition (_.age < 18)
School ! minors
Work ! adults
}
}
Асинхронность: Futures
val f: Future[List[String]] = future {
session.getRecentPosts
}
f onSuccess {
case posts =>
for (p <- posts) println(p)
}
f onFailure {
case t =>
println("An error has occurred: " + t.getMessage)
}
Combining futures with ‘for’
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")
}
Akka
● Toolkit & runtime for building concurrent,
distributed & fault tolerant applications
● Actors
● Remoting: location transparent
● Supervision & monitoring
● Software Transactional Memory
● Dataflow concurrency
Tools
IDEs: IDEA, Eclipse, NetBeans
+ Emacs, vim, Sublime, TextMate
Building: SBT
but also ant, Maven, etc...
Testing: ScalaTest, Specs, ScalaCheck
but also JUnit, EasyMock, Mockito, etc...
Web frameworks: Lift, Play!
but also Struts, Spring MVC, etc...
+ all that Java stuff
Libraries & frameworks
DB query & access: Slick (LINQ-like)
UI: ScalaFX
Text processing: parser combinators (stdlib)
GPGPU: ScalaCL
...and many others
Как правильно начать?
●
●
●
●
●

Хотя бы один эксперт - большой плюс
Не увлекайтесь фичами
Периодический рефакторинг
Используйте в юнит-тестах
Изучив Scala Вы станете лучше писать на
Java
Novosibirsk Scala Enthusiasts
Q/A
Case classes and pattern matching
● Pattern matching - обобщённый switch/case
● Case classes - реализация ADT
Преимущества Scala:
● Case class - больше чем ADT:
интерфейсы, методы, данные
● Pattern matching customizable by user:
абстракция логики от структуры данных,
DSLs
Case classes
case class Person(name: String, age: Int)

class Person(val name: String, val age: Int)
extends Serializable {
override def equals(other: AnyRef) = ...
override def hashCode = ...
override def toString = ...
def copy(name: String = this.name, age: Int = this.age) = ...
}
object Person extends (String, Int) => Person {
def apply(name: String, age: Int) = new Person
def unapply(p: Person): Option((String, Int)) =
Some((p.name, p.age))
Partial functions
trait Function1[T, R] {
def apply(x: T): R
}
trait PartialFunction[T, R] extends Function1[T, R] {
def isDefinedAt(x: T): Boolean
}
List(1,3,5,7) collect { case n if n < 5 => n + 1 }
val pf = new PartialFunction[Int, Int] {
def apply(x: Int): Int = x match
{ case n if n < 5 => n + 1 }
def isDefinedAt(x: Int): Boolean = x match
{ case n if n < 5 => true; case _ => false }
}
Promises
val 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(r)
}
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
}

Павел Павлов - Scala для Java программистов (JavaDay Nsk 28.11.2013)

  • 1.
  • 2.
    О себе Занимаюсь системнымпрограммированием ● компиляторы, среды исполнения ● Excelsior JET - JVM with AOT compiler ● код на орбите (ГЛОНАСС) Преподаю ● научное руководство студентами (НГУ) ● подготовка юниоров в компании Участник Scala community ● Scala core committer (stdlib, compiler) ● Организовал ScalaNsk
  • 3.
  • 5.
    Excelsior JET ● Полнаяреализация Java SE ○ первый релиз - 2000 год ○ с 2005 сертифицирована как Java Compatible ● AOT Compiler + Java Runtime ○ смешанная компиляция: AOT + JIT ○ поддержка нестандартных загрузчиков классов в AOT режиме (для Eclipse RCP, Tomcat) ● Toolkit ○ Deployment ○ Startup Optimizer
  • 6.
    Excelsior JET ● Однаиз 4х Java SE VM, сделанных с нуля ○ ○ ○ ○ Sun/Oracle HotSpot JRockit IBM J9 Excelsior JET ● Было: очень древний codebase ○ заложен в конце 80х/начале 90х ○ код морально устарел ○ изменилось всё: требования, технологии, инструменты, процессы ○ куда податься?
  • 7.
    Требования к языку ●Возможность создавать большие системы ○ и долгоживущие ○ и сложные ● Производительность ● статическая типизация ● развитые инструменты разработки ● промышленное качество
  • 8.
    Требования к языку ●Возможность создавать большие системы ○ и долгоживущие ○ и сложные ● Производительность ● Java и/или C++
  • 9.
    Требования к языку ●Возможность создавать большие системы ○ и долгоживущие ○ и сложные ● Производительность ● Самоприменимость ● Java
  • 10.
    Требования к языку ●Возможность создавать большие системы ○ и долгоживущие ○ и сложные ● Производительность ● Самоприменимость ● Java? А как насчёт: ○ ○ ○ ○ скорости разработки? объёма кода? гибкости, мощи средств языка? в конце концов, количества fun’а?
  • 11.
    И тут янаткнулся на Scala
  • 12.
    JET на Scala:наш опыт ● ● ● ● Оптимизирующий компилятор Новое ядро, implemented from scratch R&D "по-взрослому" Команда: ≤5 человек ○ 4 из них не знали Скалу ● Время: 1.5 года * 4 человек ○ всё работает, релиз был в апреле 2013 ○ ~40kloc
  • 13.
  • 14.
    Язык Scala: характеристика ●компилируемый ● строго статически типизированный ● автоматический вывод типов (type inference) ● OOP + FP ● "лёгкий" синтаксис ● работает на платформе JVM ● бесшовная интеграция с Java
  • 15.
    Язык Scala: цели ●Язык общего назначения ● Альтернатива/замена Java ● Внедрение FP в mainstream ● Преодоление "застоя" в OOP Целевая аудитория: 1. Java-программисты (народные массы) Лучший язык, FP 2. Ruby/Python(/JS)-программисты Статическая типизация, производительность 3. Функциональщики Использование FP в mainstream
  • 17.
  • 19.
  • 20.
  • 21.
  • 22.
    Язык Scala: история Автор:Martin Odersky (EPFL) 1995-2001 Pizza language (Odersky & Wadler) "better Java": Java + generics, function types & closures, ADT & pattern matching 1997-1998 Generic Java generics & javac compiler => Java language 2001-2005 Scala 1.x "better than Java" 2006Scala 2.x 2009-2010 Проникновение в индустрию
  • 23.
    Success story: Twitter ●2006: начало - всё на Ruby on Rails ● 2007-2008: взрывной рост популярности
  • 25.
    Success story: Twitter ●2006: начало - всё на Ruby on Rails ● 2007-2008: взрывной рост популярности Решение: +
  • 27.
    Популярность Scala ● 11место - RedMonk Programming Language Rankings (StackOverflow, GitHub) ● 36 место - TIOBE index (поисковые запросы)
  • 29.
  • 34.
  • 35.
    Hello, REPL! scala> valrepl = Map('R' -> "Read", 'E' -> "Eval", | 'P' -> "Print", 'L' -> "Loop") repl: immutable.Map[Char,String] = Map(...) scala> for ((k, v) <- repl) println(s"$k is for $v") R is for Read E is for Eval P is for Print L is for Loop
  • 36.
    Синтаксис: values &variables val x: Int = 42 val ys = List(1, 2, 3) // y: List[Int] var z = "hello" // z: String
  • 37.
    Синтаксис: values &variables val x: Int = 42 val ys = List(1, 2, 3) // y: List[Int] var z = "hello" // z: String make val not var
  • 38.
    Синтаксис: functions val x:Int = 42 val ys = List(1, 2, 3) // y: List[Int] var z = "hello" // z: String def max(a: Int, b: Int): Int = if (a > b) a else b def inc(x: Int) = x + 1 val inc = { x: Int => x + 1 } // inc: Int => Int
  • 39.
    Синтаксис: основы val x:Int = 42 val ys = List(1, 2, 3) // y: List[Int] var z = "hello" // z: String def max(a: Int, b: Int): Int = if (a > b) a else b def inc(x: Int) = x + 1 val inc = { x: Int => x + 1 } // inc: Int => Int ys map inc // List(2, 3, 4) ys map { x => x + 1 } ys map { _ + 1 } ys filter { _ % 2 != 0 } // List(1, 3) ys reduce max // max(1, max(2, 3)) ys reduce { (x, y) => x + y } // 1 + 2 + 3
  • 40.
    Классы и объекты abstractclass Animal { def name: String } class Person(firstName: String, lastName: String) extends Animal { val name = firstName + " " + lastName } class Employee(firstName: String, lastName: String, val age: Int, var salary: Double) extends Person(firstName, lastName) object Main extends App { val p = new Employee("John", "Doe", 20, 300.0) println(p.name + " is + p.age + " years old") }
  • 41.
    Traits: множественное наследование счеловеческим лицом trait Ordered[A] { def compare(that: A): Int def < (that: A): Boolean = (this compare that) < 0 def > (that: A): Boolean = (this compare that) > 0 def <= (that: A): Boolean = (this compare that) <= 0 def >= (that: A): Boolean = (this compare that) >= 0 } class Money extends SomeTrait with Ordered[Money] { def compare(that: Money) = ... }
  • 42.
  • 43.
    Operators are methods List(1,2, 3).map(inc) // List(2, 3, 4) List(1, 2, 3) map inc // <- операторный синтаксис abstract class Set[T] { def contains(x: T): Boolean def - (x: T): Set[T] def !@#%^&*-+ : Int // <- пожалуй, так делать не стоит } def foo(s: Set[Int]) { if (s contains 42) println(s - 42) } 1 + 3*5 => 1.+(3.*(5))
  • 44.
    Functions are objects Функциональныетипы: (A => B) trait Function1[A, B] { def apply(x: A): B } val inc = { x: Int => x + 1 } val inc = new Function1[Int, Int] { def apply(x: Int): Int = { x + 1 } } inc(4) // inc.apply(4) // Function1[A, B]
  • 45.
    Вызов и индексация valinverse = { x: Int => 1.0 / x } inverse(1) // => inverse.apply(1) val a = Array(0.33, 0.5) // => Array.apply(0.33, 0.5) a(1) /*0.5*/ // => a.apply(1) a(0) = 1.0 // => a.update(0, 1.0) def foo(f: Int => Double) { println(f(1)) // => println(f.apply(1)) } foo(inverse) // 1.0 foo(a) // 0.5 Array[T] is a function (Int => T)!
  • 46.
    Pattern matching val anything:Any = ... val str = anything match { case 1 => "one" case x: Int if x > 0 => "positive integer" case x: Float if x > 0 => "positive float" case _: String => "string" case _ => "unknown" } “switch/case на стероидах”
  • 47.
    Алгебраические типы type List[T]= Nil | Cons(head: T, tail: List[T]) type Option[T] = None | Some(value: T) type Tree[T] = Leaf | Branch(l, r: Tree[T], value: T)
  • 48.
    ADT in action sealedclass Expr case class Var(name: String) extends Expr case class Num(value: Int) extends Expr case class Neg(arg: Expr) extends Expr case class Add(arg1: Expr, arg2: Expr) extends Expr def optimize(expr: Expr): Expr = expr match { case Neg(Neg(x)) => optimize(x) case Add(x, Num(0)) => optimize(x) case Neg(Num(x)) => Num(-x) case Add(x, Neg(y)) if x == y => Num(0) case Add(Num(x), Num(y)) case Neg(x) => Neg(optimize(x)) case Add(x, y) => Add(optimize(x), optimize(y)) case _ } => Num(x + y) => expr
  • 49.
    Pattern matching: extractors objectPowerOfTwo { import java.lang.Long.{numberOfLeadingZeros => nlz} def apply(i: Int): Long = 1L << i def unapply(x: Long): Option[Int] = if (((x & (x-1)) == 0) && (x > 0)) Some(63 - nlz(x)) else None } def optimize(e: Expr) = e match { case Mul(x, PowerOfTwo(n)) => Shl(x, n) case Div(x, PowerOfTwo(n)) => Shr(x, n) case Rem(x, PowerOfTwo(n)) => And(x, PowerOfTwo(n) - 1) }
  • 50.
    Коллекции & итерация Коллекции- первая по важности вещь после собственно языковых фич ● Они вездесущи ● Дизайн стандартной библиотеки коллекций влияет на каждую программу, причём в значительной степени ● Они формируют словарь, с помощью которого программист выражает свои мысли
  • 51.
  • 52.
    Scala Collections: API ●functional-style ● collect, count, exists, filter, find, flatMap, fold, forall, ● foreach, groupBy, map, max/min, partition, reduce, splitAt, take, to, ... примеры: val people: Seq[Person] = ... val (minors, adults) = people partition (_.age < 18) ● параллельные коллекции: .par, tuning (thread pools etc.)
  • 53.
    for comprehension ● обобщённыйцикл for ○ с поддержкой фильтров и pattern matching ● ● ● ● преобразователь потоков данных язык запросов монадический комбинатор всего лишь синтаксический сахар
  • 54.
    for loop: basicform val files: Seq[File] = ... for (file <- files) { println(file.getName) } files foreach { file => println(file.getName) } val names = for (file <- files) yield file.getName val names = files map { _.getName }
  • 55.
    for loop: filters& nested loops def content(f: File): Seq[String] = ??? for { file <- files if !file.getName.startsWith(".") line <- content(file) if line.nonEmpty } println(file + ": " + line) files withFilter (!_.getName.startsWith(".")) foreach { file => content(file) withFilter (_.nonEmpty) foreach { line => println(file + ": " + line) } }
  • 56.
    for loop: filters& nested loops def content(f: File): Seq[String] = ??? val lines = for { file <- files if !file.getName.startsWith(".") line <- content(file) if line.nonEmpty } yield file + ": " + line files withFilter (!_.getName.startsWith(".")) flatMap { file => content(file) withFilter (_.nonEmpty) map { line => file + ": " + line } }
  • 57.
  • 58.
  • 60.
    Строковые интерполяторы val name= "John" s"Hello, $name" // то же, что "Hello, " + name println(f"$companyName%15s") val a: Int = b"100011" sql"select * from user where id = $id"
  • 61.
    Строковые интерполяторы Простейший html-интерполятордля Play: val link = "http://example.com" val userName = "Joe" val content = html""" <img src="user.png"/> $userName""" val result = html""" <a href="$link">$content</a>"""
  • 62.
    Строковые интерполяторы Простейший html-интерполятордля Play: implicit class HtmlInterpolatorHelper(val sc: StringContext) extends AnyVal { def html(args: Any*): Html = { val strings = sc.parts.iterator val expressions = args.iterator val buffer = new StringBuilder(strings.next()) while(strings.hasNext) { val nextExpr = expressions.next() nextExpr match { case html: Html => buffer.append(html.toString) case other => buffer.append(HtmlFormat.escape(other.toString)) } buffer.append(strings.next()) } new Html(buffer) } }
  • 63.
    Parallelism & concurrency valpeople: Seq[Person] = ... val (minors, adults) = people partition (_.age < 18)
  • 64.
    Parallelism & concurrency valpeople: Seq[Person] = ... val (minors, adults) = people.par partition (_.age < 18)
  • 65.
    Parallelism & concurrency valpeople: Seq[Person] = ... val (minors, adults) = people.par partition (_.age < 18) actor { receive { case people: Seq[Person] => val (minors, adults) = people partition (_.age < 18) School ! minors Work ! adults } }
  • 66.
    Асинхронность: Futures val f:Future[List[String]] = future { session.getRecentPosts } f onSuccess { case posts => for (p <- posts) println(p) } f onFailure { case t => println("An error has occurred: " + t.getMessage) }
  • 67.
    Combining futures with‘for’ 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") }
  • 68.
    Akka ● Toolkit &runtime for building concurrent, distributed & fault tolerant applications ● Actors ● Remoting: location transparent ● Supervision & monitoring ● Software Transactional Memory ● Dataflow concurrency
  • 69.
    Tools IDEs: IDEA, Eclipse,NetBeans + Emacs, vim, Sublime, TextMate Building: SBT but also ant, Maven, etc... Testing: ScalaTest, Specs, ScalaCheck but also JUnit, EasyMock, Mockito, etc... Web frameworks: Lift, Play! but also Struts, Spring MVC, etc... + all that Java stuff
  • 70.
    Libraries & frameworks DBquery & access: Slick (LINQ-like) UI: ScalaFX Text processing: parser combinators (stdlib) GPGPU: ScalaCL ...and many others
  • 71.
    Как правильно начать? ● ● ● ● ● Хотябы один эксперт - большой плюс Не увлекайтесь фичами Периодический рефакторинг Используйте в юнит-тестах Изучив Scala Вы станете лучше писать на Java
  • 72.
  • 73.
  • 74.
    Case classes andpattern matching ● Pattern matching - обобщённый switch/case ● Case classes - реализация ADT Преимущества Scala: ● Case class - больше чем ADT: интерфейсы, методы, данные ● Pattern matching customizable by user: абстракция логики от структуры данных, DSLs
  • 75.
    Case classes case classPerson(name: String, age: Int) class Person(val name: String, val age: Int) extends Serializable { override def equals(other: AnyRef) = ... override def hashCode = ... override def toString = ... def copy(name: String = this.name, age: Int = this.age) = ... } object Person extends (String, Int) => Person { def apply(name: String, age: Int) = new Person def unapply(p: Person): Option((String, Int)) = Some((p.name, p.age))
  • 76.
    Partial functions trait Function1[T,R] { def apply(x: T): R } trait PartialFunction[T, R] extends Function1[T, R] { def isDefinedAt(x: T): Boolean } List(1,3,5,7) collect { case n if n < 5 => n + 1 } val pf = new PartialFunction[Int, Int] { def apply(x: Int): Int = x match { case n if n < 5 => n + 1 } def isDefinedAt(x: Int): Boolean = x match { case n if n < 5 => true; case _ => false } }
  • 77.
    Promises val 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(r) }
  • 78.
    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 }