Successfully reported this slideshow.
We use your LinkedIn profile and activity data to personalize ads and to show you more relevant ads. You can change your ad preferences anytime.

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

882 views

Published on

Published in: Technology, News & Politics
  • Be the first to comment

  • Be the first to like this

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

  1. 1. Scala для Java программистов Павел Павлов
  2. 2. О себе Занимаюсь системным программированием ● компиляторы, среды исполнения ● Excelsior JET - JVM with AOT compiler ● код на орбите (ГЛОНАСС) Преподаю ● научное руководство студентами (НГУ) ● подготовка юниоров в компании Участник Scala community ● Scala core committer (stdlib, compiler) ● Организовал ScalaNsk
  3. 3. Одна история из реальной жизни
  4. 4. Excelsior JET ● Полная реализация Java SE ○ первый релиз - 2000 год ○ с 2005 сертифицирована как Java Compatible ● AOT Compiler + Java Runtime ○ смешанная компиляция: AOT + JIT ○ поддержка нестандартных загрузчиков классов в AOT режиме (для Eclipse RCP, Tomcat) ● Toolkit ○ Deployment ○ Startup Optimizer
  5. 5. Excelsior JET ● Одна из 4х Java SE VM, сделанных с нуля ○ ○ ○ ○ Sun/Oracle HotSpot JRockit IBM J9 Excelsior JET ● Было: очень древний codebase ○ заложен в конце 80х/начале 90х ○ код морально устарел ○ изменилось всё: требования, технологии, инструменты, процессы ○ куда податься?
  6. 6. Требования к языку ● Возможность создавать большие системы ○ и долгоживущие ○ и сложные ● Производительность ● статическая типизация ● развитые инструменты разработки ● промышленное качество
  7. 7. Требования к языку ● Возможность создавать большие системы ○ и долгоживущие ○ и сложные ● Производительность ● Java и/или C++
  8. 8. Требования к языку ● Возможность создавать большие системы ○ и долгоживущие ○ и сложные ● Производительность ● Самоприменимость ● Java
  9. 9. Требования к языку ● Возможность создавать большие системы ○ и долгоживущие ○ и сложные ● Производительность ● Самоприменимость ● Java? А как насчёт: ○ ○ ○ ○ скорости разработки? объёма кода? гибкости, мощи средств языка? в конце концов, количества fun’а?
  10. 10. И тут я наткнулся на Scala
  11. 11. JET на Scala: наш опыт ● ● ● ● Оптимизирующий компилятор Новое ядро, implemented from scratch R&D "по-взрослому" Команда: ≤5 человек ○ 4 из них не знали Скалу ● Время: 1.5 года * 4 человек ○ всё работает, релиз был в апреле 2013 ○ ~40kloc
  12. 12. Что такое Scala?
  13. 13. Язык Scala: характеристика ● компилируемый ● строго статически типизированный ● автоматический вывод типов (type inference) ● OOP + FP ● "лёгкий" синтаксис ● работает на платформе JVM ● бесшовная интеграция с Java
  14. 14. Язык Scala: цели ● Язык общего назначения ● Альтернатива/замена Java ● Внедрение FP в mainstream ● Преодоление "застоя" в OOP Целевая аудитория: 1. Java-программисты (народные массы) Лучший язык, FP 2. Ruby/Python(/JS)-программисты Статическая типизация, производительность 3. Функциональщики Использование FP в mainstream
  15. 15. Java C# Ruby Erlang JavaScript Python C Clojure Haskell PHP C++ Go Lua Groovy
  16. 16. Язык Scala: история
  17. 17. Язык Scala: история Martin Odersky
  18. 18. Язык Scala: история Martin Odersky Philip Wadler
  19. 19. Язык 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 Проникновение в индустрию
  20. 20. Success story: Twitter ● 2006: начало - всё на Ruby on Rails ● 2007-2008: взрывной рост популярности
  21. 21. Success story: Twitter ● 2006: начало - всё на Ruby on Rails ● 2007-2008: взрывной рост популярности Решение: +
  22. 22. Популярность Scala ● 11 место - RedMonk Programming Language Rankings (StackOverflow, GitHub) ● 36 место - TIOBE index (поисковые запросы)
  23. 23. http://www.infoq.com/research/next-jvm-language
  24. 24. Инструменты
  25. 25. 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
  26. 26. Синтаксис: values & variables val x: Int = 42 val ys = List(1, 2, 3) // y: List[Int] var z = "hello" // z: String
  27. 27. Синтаксис: values & variables val x: Int = 42 val ys = List(1, 2, 3) // y: List[Int] var z = "hello" // z: String make val not var
  28. 28. Синтаксис: 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
  29. 29. Синтаксис: основы 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
  30. 30. Классы и объекты 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") }
  31. 31. 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) = ... }
  32. 32. Types hierarchy
  33. 33. 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))
  34. 34. 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]
  35. 35. Вызов и индексация 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)!
  36. 36. 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 на стероидах”
  37. 37. Алгебраические типы 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)
  38. 38. 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
  39. 39. 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) }
  40. 40. Коллекции & итерация Коллекции - первая по важности вещь после собственно языковых фич ● Они вездесущи ● Дизайн стандартной библиотеки коллекций влияет на каждую программу, причём в значительной степени ● Они формируют словарь, с помощью которого программист выражает свои мысли
  41. 41. Scala Collections
  42. 42. 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.)
  43. 43. for comprehension ● обобщённый цикл for ○ с поддержкой фильтров и pattern matching ● ● ● ● преобразователь потоков данных язык запросов монадический комбинатор всего лишь синтаксический сахар
  44. 44. 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 }
  45. 45. 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) } }
  46. 46. 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 } }
  47. 47. Implicits ● ● ● ● Extension methods Automatic adaptors DSLs Typeclass pattern (C++ concepts)
  48. 48. Internal DSLs
  49. 49. Строковые интерполяторы val name = "John" s"Hello, $name" // то же, что "Hello, " + name println(f"$companyName%15s") val a: Int = b"100011" sql"select * from user where id = $id"
  50. 50. Строковые интерполяторы Простейший 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>"""
  51. 51. Строковые интерполяторы Простейший 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) } }
  52. 52. Parallelism & concurrency val people: Seq[Person] = ... val (minors, adults) = people partition (_.age < 18)
  53. 53. Parallelism & concurrency val people: Seq[Person] = ... val (minors, adults) = people.par partition (_.age < 18)
  54. 54. 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 } }
  55. 55. Асинхронность: 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) }
  56. 56. 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") }
  57. 57. Akka ● Toolkit & runtime for building concurrent, distributed & fault tolerant applications ● Actors ● Remoting: location transparent ● Supervision & monitoring ● Software Transactional Memory ● Dataflow concurrency
  58. 58. 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
  59. 59. Libraries & frameworks DB query & access: Slick (LINQ-like) UI: ScalaFX Text processing: parser combinators (stdlib) GPGPU: ScalaCL ...and many others
  60. 60. Как правильно начать? ● ● ● ● ● Хотя бы один эксперт - большой плюс Не увлекайтесь фичами Периодический рефакторинг Используйте в юнит-тестах Изучив Scala Вы станете лучше писать на Java
  61. 61. Novosibirsk Scala Enthusiasts
  62. 62. Q/A
  63. 63. Case classes and pattern matching ● Pattern matching - обобщённый switch/case ● Case classes - реализация ADT Преимущества Scala: ● Case class - больше чем ADT: интерфейсы, методы, данные ● Pattern matching customizable by user: абстракция логики от структуры данных, DSLs
  64. 64. 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))
  65. 65. 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 } }
  66. 66. 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) }
  67. 67. 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 }

×