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

78
Scala для Java программистов Павел Павлов

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

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

Scalaдля Java программистов

Павел Павлов

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

О себе

Занимаюсь системным программированием● компиляторы, среды исполнения● Excelsior JET - JVM with AOT compiler● код на орбите (ГЛОНАСС)

Преподаю● научное руководство студентами (НГУ)● подготовка юниоров в компании

Участник Scala community● Scala core committer (stdlib, compiler)● Организовал ScalaNsk

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

Одна история из реальной жизни

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

Excelsior JET

● Полная реализация Java SE○ первый релиз - 2000 год○ с 2005 сертифицирована как Java Compatible

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

AOT режиме (для Eclipse RCP, Tomcat)● Toolkit

○ Deployment○ Startup Optimizer

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

Excelsior JET

● Одна из 4х Java SE VM, сделанных с нуля○ Sun/Oracle HotSpot○ JRockit○ IBM J9○ Excelsior JET

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

инструменты, процессы○ куда податься?

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

Требования к языку

● Возможность создавать большие системы○ и долгоживущие○ и сложные

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

● статическая типизация● развитые инструменты разработки● промышленное качество

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

Требования к языку

● Возможность создавать большие системы○ и долгоживущие○ и сложные

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

● Java и/или C++

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

Требования к языку

● Возможность создавать большие системы○ и долгоживущие○ и сложные

● Производительность● Самоприменимость

● Java

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

Требования к языку

● Возможность создавать большие системы○ и долгоживущие○ и сложные

● Производительность● Самоприменимость

● Java? А как насчёт:○ скорости разработки?○ объёма кода?○ гибкости, мощи средств языка?○ в конце концов, количества fun’а?

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

И тут я наткнулся на Scala

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

JET на Scala: наш опыт

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

○ 4 из них не знали Скалу● Время: 1.5 года * 4 человек

○ всё работает, релиз был в апреле 2013○ ~40kloc

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

Что такое Scala?

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

Язык Scala: характеристика

● компилируемый● строго статически типизированный● автоматический вывод типов (type

inference)● OOP + FP● "лёгкий" синтаксис● работает на платформе JVM● бесшовная интеграция с Java

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

Язык Scala: цели● Язык общего назначения● Альтернатива/замена Java● Внедрение FP в mainstream● Преодоление "застоя" в OOPЦелевая аудитория:1. Java-программисты (народные массы)

Лучший язык, FP

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

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

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

JavaRuby

C++

C#

Clojure

Haskell

JavaScript

Erlang

Python

Lua

Go

C

Groovy

PHP

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

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

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

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

Martin Odersky

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

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

Martin Odersky Philip Wadler

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

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

Автор: Martin Odersky (EPFL)1995-2001 Pizza language (Odersky & Wadler)

"better Java": Java + generics, function types & closures, ADT & pattern matching

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

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

2006- Scala 2.x2009-2010 Проникновение в индустрию

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

Success story: Twitter

● 2006: начало - всё на Ruby on Rails● 2007-2008: взрывной рост популярности

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

Success story: Twitter

● 2006: начало - всё на Ruby on Rails● 2007-2008: взрывной рост популярности

Решение:

+

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

Популярность Scala

● 11 место - RedMonk Programming Language Rankings (StackOverflow, GitHub)

● 36 место - TIOBE index(поисковые запросы)

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

http://www.infoq.com/research/next-jvm-language

Page 30: Павел Павлов - Scala для Java программистов (JavaDay Nsk 28.11.2013)
Page 31: Павел Павлов - Scala для Java программистов (JavaDay Nsk 28.11.2013)
Page 32: Павел Павлов - Scala для Java программистов (JavaDay Nsk 28.11.2013)
Page 33: Павел Павлов - Scala для Java программистов (JavaDay Nsk 28.11.2013)
Page 34: Павел Павлов - Scala для Java программистов (JavaDay Nsk 28.11.2013)

Инструменты

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

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

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

Синтаксис: values & variablesval x: Int = 42

val ys = List(1, 2, 3) // y: List[Int]

var z = "hello" // z: String

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

val x: Int = 42

val ys = List(1, 2, 3) // y: List[Int]

var z = "hello" // z: String

Синтаксис: values & variables

make val not var

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

Синтаксис: functionsval 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

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

Синтаксис: основы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

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

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")

}

Классы и объекты

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

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) = ...

}

Traits: множественное наследованиес человеческим лицом

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

Types hierarchy

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

Operators are methodsList(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))

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

Функциональные типы: (A => B) // Function1[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)

Functions are objects

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

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)!

Вызов и индексация

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

Pattern matchingval 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 на стероидах”

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

Алгебраические типы

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)

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

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)) => Num(x + y)

case Neg(x) => Neg(optimize(x))

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

case _ => expr

}

ADT in action

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

Pattern matching: extractorsobject 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)

}

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

Коллекции & итерация

Коллекции - первая по важности вещь после собственно языковых фич● Они вездесущи● Дизайн стандартной библиотеки коллекций

влияет на каждую программу, причём в значительной степени

● Они формируют словарь, с помощью которого программист выражает свои мысли

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

Scala Collections

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

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.)

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

for comprehension

● обобщённый цикл for○ с поддержкой фильтров и pattern matching

● преобразователь потоков данных● язык запросов● монадический комбинатор● всего лишь синтаксический сахар

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

for loop: basic formval 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 }

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

for loop: filters & nested loopsdef 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)

}

}

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

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

}

}

for loop: filters & nested loops

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

Implicits

● Extension methods● Automatic adaptors● DSLs● Typeclass pattern (C++ concepts)

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

Internal DSLs

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

Строковые интерполяторы

val name = "John"s"Hello, $name" // то же, что "Hello, " + name

println(f"$companyName%15s") val a: Int = b"100011" sql"select * from user where id = $id"

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

Строковые интерполяторы

Простейший 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>"""

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

Строковые интерполяторы

Простейший 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) } }

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

Parallelism & concurrencyval people: Seq[Person] = ...

val (minors, adults) = people partition (_.age < 18)

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

Parallelism & concurrencyval people: Seq[Person] = ...

val (minors, adults) = people.par partition (_.age < 18)

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

Parallelism & concurrencyval 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

}

}

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

Асинхронность: Futuresval 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)

}

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

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")

}

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

Akka

● Toolkit & runtime for building concurrent, distributed & fault tolerant applications

● Actors● Remoting: location transparent● Supervision & monitoring● Software Transactional Memory● Dataflow concurrency

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

Tools

IDEs: IDEA, Eclipse, NetBeans+ Emacs, vim, Sublime, TextMate

Building: SBTbut also ant, Maven, etc...

Testing: ScalaTest, Specs, ScalaCheckbut also JUnit, EasyMock, Mockito, etc...

Web frameworks: Lift, Play!but also Struts, Spring MVC, etc...

+ all that Java stuff

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

Libraries & frameworks

DB query & access: Slick (LINQ-like)UI: ScalaFXText processing: parser combinators (stdlib)GPGPU: ScalaCL...and many others

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

Как правильно начать?

● Хотя бы один эксперт - большой плюс● Не увлекайтесь фичами● Периодический рефакторинг● Используйте в юнит-тестах● Изучив Scala Вы станете лучше писать на

Java

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

Novosibirsk Scala Enthusiasts

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

Q / A

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

Case classes and pattern matching

● Pattern matching - обобщённый switch/case● Case classes - реализация ADT

Преимущества Scala:● Case class - больше чем ADT:

интерфейсы, методы, данные● Pattern matching customizable by user:

абстракция логики от структуры данных, DSLs

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

Case classescase 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))

}

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

Partial functionstrait 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 }

}

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

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(r)

}

}

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

Promisesdef 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

}