scala: что, как и зачем?

55
Что, как и зачем? Тимушев Роман

Upload: roman-timushev

Post on 25-Jan-2015

233 views

Category:

Software


6 download

DESCRIPTION

 

TRANSCRIPT

Page 1: Scala: что, как и зачем?

Что, как и зачем?

Тимушев Роман

Page 2: Scala: что, как и зачем?

ОБО МНЕ

• Scala с 2011

• Один из организаторов встреч Scala Moscow User Group

• Работаю в Qubell

Page 3: Scala: что, как и зачем?

О ВАС

• Кто из вас

• пишет на Java?

• слышал о Scala?

• пишет на Scala?

• слышал что такое монада?

• понимает, что монада это моноид в категории эндофункторов?

Page 4: Scala: что, как и зачем?

ЧТО ТАКОЕ SCALA• Язык существует с 2003г.

• Scalable language

• Объединяет в себе OO и ФП-концепции

• Статически типизирован

• Компилируется в java-байткод

• Open source

Page 5: Scala: что, как и зачем?

ПЕРЕМЕННЫЕ И ЗНАЧЕНИЯ

var a: String = "foo"!a = "bar" // разрешено!!val b: String = "foo"!b = "bar" // запрещено

Page 6: Scala: что, как и зачем?

ФУНКЦИИ

def sum1(a: Int, b: Int): Int =! a + b!!val sum2 =! (a: Int, b: Int) => a + b!!val sum3: (Int, Int) => Int =! (a, b) => a + b!!val sum4: (Int, Int) => Int =! _ + _

Page 7: Scala: что, как и зачем?

КЛАССЫ, ОБЪЕКТЫ И ТРЕЙТЫ

trait Dumpable {! def dump: String! def dump(out: PrintStream) { out.print(dump) }!}!!class Foo extends Dumpable {! override def dump = "Foo"!}!!val foo = new Foo!foo.dump(Console.out)!!object Bar extends Dumpable {! override def dump = "Bar"!}!!Bar.dump(Console.err)

Page 8: Scala: что, как и зачем?

СИСТЕМА ТИПОВ• Всё есть объект: Any, AnyVal, AnyRef

• Кортежи:scala> val tuple = (1, "a", true)!tuple: (Int, String, Boolean) = (1,a,true)!!scala> tuple._2!res0: String = a!!scala> val (x, y, _) = tuple!x: Int = 1!y: String = a

Page 9: Scala: что, как и зачем?

КТО ИСПОЛЬЗУЕТ SCALA

Page 10: Scala: что, как и зачем?

ЧТО ЭТО, МОДА?

If I were to pick a language today other than Java, it would be Scala.

!James Gosling,father of Java

Page 11: Scala: что, как и зачем?

ВЫБОР ЯЗЫКА

• Совместимость

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

• Поддержка

• Продуктивность

Page 12: Scala: что, как и зачем?

СОВМЕСТИМОСТЬ• Работает на платформе JVM

• Windows, Mac, Linux, Android, кофеварки

• Отличный JIT-компилятор

• Отличный GC

• Прозрачно интегрируется с Java-кодом

• Смешанная компиляция

• Можно использовать все доступные java-библиотеки

• Старый код можно тоже не переписывать

Page 13: Scala: что, как и зачем?

ПРОИЗВОДИТЕЛЬНОСТЬ

• Какой код напишете, так и будет

• Производительность сравнима с Java

• Обычно потребляет немного больше памяти, чем Java

Page 14: Scala: что, как и зачем?

ПОДДЕРЖКА

• Коммерческая поддержка от Typesafe Inc.

• Дружелюбное сообщество

Page 15: Scala: что, как и зачем?

ПРОДУКТИВНОСТЬ

Сложно вернуться на Java без боли

Page 16: Scala: что, как и зачем?

РАЗМЕР КОДА JAVApublic class Person {! ! private final String name;! private final int age;!! public Person(String name, int age) {! this.name = name;! this.age = age;! }!! public String getName() {! return name;! }!! public int getAge() {! return age;! }!! @Override! public String toString() {! return "Person(" + name + ", " + age + ")";! }!! @Override! public boolean equals(Object o) {! if (this == o) return true;! if (o == null || getClass() != o.getClass()) return false;! Person person = (Person) o;! if (age != person.age) return false;! if (name != null ? !name.equals(person.name) : person.name != null) return false;! return true;! }!! @Override! public int hashCode() {! int result = name != null ? name.hashCode() : 0;! result = 31 * result + age;! return result;! }!!}

Page 17: Scala: что, как и зачем?

РАЗМЕР КОДА SCALA

+ Метод-фабрика

+ Метод copy

+ Деконструктор для pattern matching

case class Person(name: String, age: Int)

Page 18: Scala: что, как и зачем?

РАЗМЕР ИМЕЕТ ЗНАЧЕНИЕ

• Число ошибок на строку кода — константа слабо зависящая от языка программирования

• В поле зрения человека попадает ограниченный объём кода

• Человек может сфокусировать внимание на определённом объёме информации

Page 19: Scala: что, как и зачем?

ВЫВОД ТИПОВ• Scala ! ! val list = new ListBuffer[String]()!

• Java ! ! ArrayList<String> list = new ArrayList<>();!

• Scala ! ! val set = new HashMap[String, Int]().keySet!

• Java ! ! Set<String> set = new HashMap<String, String>().keySet();!

Page 20: Scala: что, как и зачем?

OPTION• Опциональное значение: None или Some(value)

• Многие операции можно делать не извлекая значение

• Извлечь тоже можно, но в отличие от null это делается явно

• Все библиотеки используют этот тип

• В Java 8 тоже есть Optional

Page 21: Scala: что, как и зачем?

OPTIONval capitals = Map("Russia" -> "Moscow",! "France" -> "Paris")!!val a = capitals.get("Russia")!// Some("Moscow")!val b = capitals.get("Italy") // None!!a.map(_.toUpperCase) // Some("MOSCOW")!b.map(_.toUpperCase) // None!!a.getOrElse("Unknown") // "Moscow"!b.getOrElse("Unknown") // "Unknown"!!for (x <- a; y <- b) yield s"$x, $y" // None

Page 22: Scala: что, как и зачем?

PATTERN MATCHINGsealed trait Shape!case class Circle(radius: Double) extends Shape!case class Rectangle(width: Double,! height: Double) extends Shape!!val description = shape match {! case Rectangle(w, h) if w == h =>! s"square, side $w"! case Rectangle(w, h) =>! s"rectangle, $w x $h"! case Circle(r) =>! s"circle, radius $r"!}

Page 23: Scala: что, как и зачем?

ПРОВЕРКА ПОЛНОТЫsealed trait Shape!case class Circle(radius: Double) extends Shape!case class Rectangle(width: Double,! height: Double) extends Shape!!val description = shape match {! case Circle(r) =>! s"circle, radius $r"!}!!pm.scala:16: match may not be exhaustive.!It would fail on the following input: Rectangle(_, _)! val description = shape match {! ^

Page 24: Scala: что, как и зачем?

FOR-EXPRESSIONS case class City(name: String,! streets: List[Street],! population: Int)!!case class Street(name: String,! sights: List[String])!!val cities: List[City]!!val plan = cities! .filter(_.population > 1000)! .flatMap(_.streets)! .flatMap(s => s.sights.map(s -> _))

Page 25: Scala: что, как и зачем?

FOR-EXPRESSIONS

val plan = cities! .filter(_.population > 1000)! .flatMap(_.streets)! .flatMap(s => s.sights.map(s -> _))!!val plan = for {! city <- cities if city.population > 1000! street <- city.streets! poi <- street.sights!} yield (street.name, poi)

Page 26: Scala: что, как и зачем?

НЕ ТОЛЬКО КОЛЛЕКЦИИ

def httpGet(url: String): Future[String] = ???!!def getPost(idx: Int): Future[String] =! for {! posts <- httpGet("http://localhost/posts")! slug = posts.split("\n")(idx)! post <- httpGet(s"http://localhost/$slug")! } yield post

Page 27: Scala: что, как и зачем?

AD-HOC POLYMORPHISM

trait Pretty {! def toPrettyString: String!}

Привет, Мартин. Ты не мог бы отнаследовать классы стандартной библиотеки от Pretty? Это очень

важно для нас…

Page 28: Scala: что, как и зачем?

AD-HOC POLYMORPHISM

implicit class StringPretty(x: String) extends Pretty {! def toPrettyString = x!}!!implicit class IntPretty(x: Int) extends Pretty {! def toPrettyString = x.toString!}!!implicit class ListPretty[T <% Pretty](x: List[T])! extends Pretty {! def toPrettyString =! x.map(_.toPrettyString).mkString("[", ", ", "]")!}

Page 29: Scala: что, как и зачем?

AD-HOC POLYMORPHISM

dump("Hello, Mera")!dump(List("a", "b"))!dump(42)!!// ошибка компиляции!dump(1.0)

Page 30: Scala: что, как и зачем?

ДРУГИЕ ПЛЮШКИ• Ленивые значения

• Именованые параметры

• Значения параметров по-умолчанию

• Множественное наследование

• Структурные типы

• Определение операторов

• Ко- и контра-вариантность

• Типы высших порядков

• XML-литералы

• Интерполяция строк

• Макросы

• …

Page 31: Scala: что, как и зачем?

СЛОЖНОСТЬ

object Sized extends LowPrioritySized {! implicit def sizedOps[Repr, L <: Nat](s : Sized[Repr, L])! (implicit itl: IsTraversableLike[Repr]): SizedOps[itl.A, Repr, L] =! new SizedOps[itl.A, Repr, L](itl.conversion(s.unsized))! ! def apply[CC[_]] = new SizedBuilder[CC]! ! def apply[CC[_]]()! (implicit cbf : CanBuildFrom[Nothing, Nothing, CC[Nothing]]) =! new Sized[CC[Nothing], _0](cbf().result)! ! def wrap[Repr, L <: Nat](r : Repr) = new Sized[Repr, L](r)!! def unapplySeq[Repr, L <: Nat](x : Sized[Repr, L]) = Some(x.unsized)!}

Page 32: Scala: что, как и зачем?

ПРОСТОТА

def csv[N <: Nat](hdrs: Sized[Seq[String], N],! rows: Sized[Seq[String], N]*) = ???!!csv(! Sized("ID", "Name"),! Sized("1", "Nikolay"),! Sized("2", "Vasiliy"),! // compile-time error! Sized("3", "Ivan", "Ivanovich")!)

Page 33: Scala: что, как и зачем?

БОРЬБА СО СЛОЖНОСТЬЮ• Обучение → делает сложное простым

• Административные меры → запрет писать сложный код

• Code review → понятен ли ваш код другим

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

Page 34: Scala: что, как и зачем?

ENABLING LANGUAGE FEATURES

implicit def intToString(x: Int): String = x.toString!!val x: String = 1

features.scala:7: implicit conversion method intToString should be enabled by making the implicit value scala.language.implicitConversions visible.

import scala.language.implicitConversions

Page 35: Scala: что, как и зачем?

КАДРОВЫЙ ВОПРОС• Перейти с Java на Scala для большинства не составляет проблемы

• Готовых Scala-разработчиков мало, но их число растёт

• Конкуренция на рынке вакансий ниже

• Средний уровень Scala-разработчиков выше

Page 36: Scala: что, как и зачем?

КАДРОВЫЙ ВОПРОС

• Нужна небольшая талантливая команда — Scala может оказаться предпочтительнее

• Большая команда для несложных задач —Java будет лучшим выбором

Page 37: Scala: что, как и зачем?

УГОВОРИЛ, КАК НАЧАТЬ• Пишите на Scala так же как на Java

• Начните с тестов

• Поощряйте «хороший» скала-код: Option вместо null, иммутабельность

• Желательно наличие эксперта в команде

• Некоторые IDE умеют конвертировать Java код в Scala автоматически

Page 38: Scala: что, как и зачем?

ПРОБЛЕМЫ

• Более сложные концепции

• Медленная компиляция

• Бинарная совместимость

• Недостаточная поддержка в IDE

Page 39: Scala: что, как и зачем?

ПОЛЕЗНЫЕ БИБЛИОТЕКИ

• Akka — многопоточные распределённые приложения

• Slick — работа с базами данных

• Shapeless, scalaz — выразительный и обобщённый код

• Scalatest — удобное тестирование

• SBT — система сборки

Page 40: Scala: что, как и зачем?

AKKA• Акторы — легковесные сущности, асинхронно обменивающиеся сообщениями

• О потоках и синхронизации заботится Akka

• Простой переход к распределённому приложению

• Устойчивость к ошибкам

Page 41: Scala: что, как и зачем?

ПРИМЕР AKKAclass Worker extends Actor {!! val db = DB.connect()!! override def postStop() {! db.close()! }!! def receive = {! case Query(sql) => sender() ! db.query(sql)! }!!}

Page 42: Scala: что, как и зачем?

СУПЕРВИЗОРclass Supervisor extends Actor {!! override val supervisorStrategy =! OneForOneStrategy(maxNrOfRetries = 10,! withinTimeRange = 1 minute) {! case _: IOException => Restart! case _: Exception => Escalate! }!! val worker = context.actorOf(Props[Worker])!! def receive = {! case q: Query => worker forward q! }!!}

Page 43: Scala: что, как и зачем?

POOLING

akka.actor.deployment {! /parent/workerRouter {! router = round-robin-pool! nr-of-instances = 5! }!}!!val workers = context.actorOf(! FromConfig.props(Props[Worker]),! "workerRouter"!)

Page 44: Scala: что, как и зачем?

REMOTING

akka {! actor {! deployment {! /parent/worker {! remote =! "akka.tcp://[email protected]:2553"! }! }! }!}

Page 45: Scala: что, как и зачем?

SLICK

• Схема и запросы — обычный Scala-код

• Работа с базой данных так же проста, как с обычными коллекциями

• Запросы типобезопасны

Page 46: Scala: что, как и зачем?

ПРИМЕР SLICK

// select NAME from COFFEES !// where PRICE < 10.0!// order by NAME!coffees! .filter(_.price < 10.0)! .sortBy(_.name)! .map(_.name)! .list!!// Seq[String]("Cappuccino", "Espresso")

Page 47: Scala: что, как и зачем?

БИБЛИОТЕКИ TYPELEVEL

• Scalaz — упрощает программирование в функциональном стиле (монады, функторы, линзы и другие классы типов)

• Shapeless — ещё более строгая типизация

Page 48: Scala: что, как и зачем?

SCALAZ: MONOIDS

val x = Map("a" -> List(1))!!val y = Map("a" -> List(2),! "b" -> List(3))!!// or println(x mappend y)!println(x |+| y)!!"Map(a -> List(1, 2), b -> List(3))"

Page 49: Scala: что, как и зачем?

SHAPELESS: TYPE-SAFE CAST

// опасно!x.asInstanceOf[Map[String, List[Int]]]!!// безопасно!x.cast[Map[String, List[Int]]]

Page 50: Scala: что, как и зачем?

SCALATEST

class ExampleSpec extends FreeSpec with Matchers {! "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 be (2)! stack.pop() should be (1)! }! it should "throw NoSuchElementException if an empty stack is popped" in {! val emptyStack = new Stack[Int]! a [NoSuchElementException] should be thrownBy {! emptyStack.pop()! } ! }!}

Page 51: Scala: что, как и зачем?

SCALATEST

$ scala -cp scalatest_2.11-2.2.0.jar org.scalatest.run ExampleSpecDiscovery starting.Discovery completed in 21 milliseconds.Run starting. Expected test count is: 2ExampleSpec:A Stack- should pop values in last-in-first-out order- should throw NoSuchElementException if an empty stack is poppedRun completed in 76 milliseconds.Total number of tests run: 2Suites: completed 1, aborted 0Tests: succeeded 2, failed 0, canceled 0, ignored 0, pending 0All tests passed.

Page 52: Scala: что, как и зачем?

ASSERTIONS

scala> assert(a == b || c >= d) org.scalatest.exceptions.TestFailedException: 1 did not equal 2, and 3 was not greater than or equal to 4 at ... !scala> assert(Some(2).isEmpty) org.scalatest.exceptions.TestFailedException: Some(2) was not empty at ...

Page 53: Scala: что, как и зачем?

DIAGRAMMED ASSERTIONS

scala> assert(a == b || c >= d) org.scalatest.exceptions.TestFailedException: !assert(a == b || c >= d) | | | | | | | 1 | 2 | 3 | 4 | | false | false false ! at ...

Page 54: Scala: что, как и зачем?

СПАСИБО ЗА ВНИМАНИЕ ВОПРОСЫ?

Page 55: Scala: что, как и зачем?

ССЫЛКИ• http://www.scala-lang.org/

• http://typesafe.com/platform/

• http://typelevel.org/

• http://www.scalatest.org/

• http://notes.implicit.ly/