Scala

  • 396 views
Uploaded on

 

More in: Technology
  • Full Name Full Name Comment goes here.
    Are you sure you want to
    Your message goes here
    Be the first to comment
    Be the first to like this
No Downloads

Views

Total Views
396
On Slideshare
0
From Embeds
0
Number of Embeds
3

Actions

Shares
Downloads
3
Comments
0
Likes
0

Embeds 0

No embeds

Report content

Flagged as inappropriate Flag as inappropriate
Flag as inappropriate

Select your reason for flagging this presentation as inappropriate.

Cancel
    No notes for slide

Transcript

  • 1. def scala = oop + fpПавел Павлов
  • 2. О себеЗанимаюсь системным программированием● компиляторы, среды исполнения● Excelsior JET - JVM with AOT compiler● код на орбите (ГЛОНАСС)Преподаю● научное руководство студентами (НГУ)● подготовка юниоров в компанииУчастник Scala community● Scala core committer (stdlib, compiler)● Организовал ScalaNsk
  • 3. Язык Scala: характеристика● компилируемый● строго статически типизированный● автоматический вывод типов● OOP + FP● "лёгкий" синтаксис● работает на платформе JVM● бесшовная интеграция с Java
  • 4. Язык Scala: цели● Язык общего назначения● Альтернатива/замена Java● Внедрение FP в mainstream● Преодоление "застоя" в OOPЦелевая аудитория:1. Java-программисты (народные массы)Лучший язык, FP2. Ruby/Python(/JS)-программистыСтатическая типизация, производительность3. ФункциональщикиИспользование FP в mainstream
  • 5. Язык Scala: история
  • 6. Язык Scala: историяMartin Odersky
  • 7. Язык Scala: историяMartin Odersky Philip Wadler
  • 8. Язык Scala: историяАвтор: Martin Odersky (EPFL)1995-2001 Pizza language (Odersky & Wadler)"better Java": Java + generics, function types &closures, ADT & pattern matching1997-1998 Generic Javagenerics & javac compiler => Java language2001-2005 Scala 1.x"better than Java"2006- Scala 2.x2009-2010 Проникновение в индустрию
  • 9. Язык Scala: популярность● 11 место - RedMonk Programming LanguageRankings (StackOverflow, GitHub)● 36 место - TIOBE index(поисковые запросы)
  • 10. http://www.infoq.com/research/next-jvm-language
  • 11. Success story: Twitter● 2006: начало - всё на Ruby on Rails● 2007-2008: взрывной рост популярности
  • 12. Success story: Twitter● 2006: начало - всё на Ruby on Rails● 2007-2008: взрывной рост популярностиРешение:+
  • 13. 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 ReadE is for EvalP is for PrintL is for Loop
  • 14. Синтаксис: values & variablesval x: Int = 42val ys = List(1, 2, 3) // y: List[Int]var z = "hello" // z: String
  • 15. Синтаксис: values & variablesval x: Int = 42val ys = List(1, 2, 3) // y: List[Int]var z = "hello" // z: Stringmake val not var
  • 16. Синтаксис: functionsval x: Int = 42val ys = List(1, 2, 3) // y: List[Int]var z = "hello" // z: Stringdef max(a: Int, b: Int): Int = if (a > b) a else bdef inc(x: Int) = x + 1val inc = { x: Int => x + 1 } // inc: Int => Int
  • 17. Синтаксис: основыval x: Int = 42val ys = List(1, 2, 3) // y: List[Int]var z = "hello" // z: Stringdef max(a: Int, b: Int): Int = if (a > b) a else bdef inc(x: Int) = x + 1val inc = { x: Int => x + 1 } // inc: Int => Intys 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
  • 18. 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")}Классы и объекты
  • 19. trait Ordered[A] {def compare(that: A): Intdef < (that: A): Boolean = (this compare that) < 0def > (that: A): Boolean = (this compare that) > 0def <= (that: A): Boolean = (this compare that) <= 0def >= (that: A): Boolean = (this compare that) >= 0}class Money extends SomeTrait with Ordered[Money] {def compare(that: Money) = ...}Traits: множественное наследованиес человеческим лицом
  • 20. Scala = OOP + FPКак скрестить ужа с ежом?1. дешёвая китайская имитацияJava 8 lambdas2. мухи отдельно, котлеты отдельно3. кодируем объекты функциями4. кодируем функции объектами: Scala wayScala = OO kernel + syntactic sugar
  • 21. Синтаксический сахар● бесскобочные методы● auto-generated accessors● операторы = методы,● операторный синтаксис● apply, update● for loop● case classes, unapply● implicitsДля чего? UAP, DSLs, extension methods, FP->OOP mapping, pattern matching
  • 22. Uniform Access PrincipleВсе услуги, предлагаемые модулем должныбыть доступны через единую нотацию,которая не раскрывает, реализованы ли онипосредством хранения либо вычисления.Bertrand Meyer
  • 23. class Foo(val r1: Int) { // <- auto-generated gettervar rw1: Int // <- auto-generated getter & setterdef r2: Int = ???private[this] var _field = 0def rw2: Int = _fielddef rw2_=(x: Int) { _field = x }}val v: Foo = ...println(v.r1 + v.r2 + v.rw1 + v.rw2)v.rw1 = 42v.rw2 = 43 // v.rw2_=(43)UAP: fields, methods and properties
  • 24. Methods and operatorsList(1, 2, 3).map(inc) // List(2, 3, 4)List(1, 2, 3) map inc // <- операторный синтаксисabstract class Set[T] {def contains(x: T): Booleandef - (x: T): Set[T]def !@#%^&*-+ : Int // <- пожалуй, так делать нестоит}def foo(s: Set[Int]) {if (s contains 42) println(s - 42)}1 + 3*5 => 1.+(3.*(5))
  • 25. 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.0foo(a) // 0.5Array[T] is a function (Int => T)!Вызов и индексация
  • 26. Функциональные типы:(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)Функции как объекты
  • 27. Case classes and pattern matching● Pattern matching - обобщённый switch/case● Case classes - реализация ADTПреимущества Scala:● Case class - больше чем ADT:интерфейсы, методы, данные● Pattern matching customizable by user:абстракция логики от структуры данных,DSLs
  • 28. 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 Persondef unapply(p: Person): Option((String, Int)) =Some((p.name, p.age))}
  • 29. Case classes as ADTcase class Person(name: String, age: Int)val p = Person("John", 20)println(p) // Person(John,20)val q = p.copy(name="Sam")q.copy(age = q.age+1) == Person("Sam", 21) // truedef foo(x: Any) = x match {case Person(name, age) => s"$name of $age years"case _ => x.toString}foo(p) // "John of 20 years"foo(123) // "123"
  • 30. 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"}
  • 31. sealed class Exprcase class Var(name: String) extends Exprcase class Num(value: Int) extends Exprcase class Neg(arg: Expr) extends Exprcase class Add(arg1: Expr, arg2: Expr) extends Exprdef 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
  • 32. Extractor objectsobject PowerOfTwo {import java.lang.Long.{numberOfLeadingZeros => nlz}def apply(i: Int): Long = 1L << idef 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)}
  • 33. Pattern matching everywheredef foo(x: Int) = (x, x*x*x) // Int => (Int, Int)val xs = List(1,2,3) map foo // List((1,1),(2,8),(3,27))val (n, c) = xs.last // n = 3, c = 27for ((n, c) <- xs) println(c/n) // 1, 4, 9val zs = xs collect { case (x, y) if x < y => y - x }println(zs) // List(6,24)
  • 34. Partial functionsclass List[T] {def collect[U](pf: PartialFunction[T,U]): List[U] = {val buf: Buffer[U] = ...for(elem <- this) if(pf isDefinedAt elem) buf += pf(elem)buf.toList}}val zs = xs collect { case (x, y) if x < y => y - x }println(zs) // List(6,24)
  • 35. Types hierarchy
  • 36. Типы● value & reference types● top & bottom types● compound types● параметризация (generics)○ variance: co- & contra-○ upper & lower bounds● higher-kinded types● abstract types● self types● dependent types● structural types (typesafe duck typing)
  • 37. А также● mixin composition● implicits: extension methods, type classes● typesafe dependency injection● compound types● structural & dynamic types● delimited continuations● scala reflection● ...и многое другое
  • 38. Internal DSLs
  • 39. Macrosdef assert(cond: Boolean, msg: Any) = macro Asserts.assertImplobject Asserts {def raise(msg: Any) = throw new AssertionError(msg)def assertImpl(c: Context)(cond: c.Expr[Boolean], msg: c.Expr[Any]): c.Expr[Unit] =if (assertionsEnabled)reify { if (!cond.splice) raise(msg.splice) }elsereify { () }}assert(c, "msg") => if(!c) raise("msg")
  • 40. Scala Collections
  • 41. 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 poolsetc.)
  • 42. for comprehension● обобщённый цикл for○ с поддержкой фильтров и pattern matching● преобразователь потоков данных● язык запросов● монадический комбинатор● всего лишь синтаксический сахар
  • 43. 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.getNameval names = files map { _.getName }
  • 44. for loop: filters & nested loopsdef content(f: File): Seq[String] = ???for (file <- files) {if (!file.getName.startsWith(".")) {for (line <- content(file)) {if (line.nonEmpty) {println(file + ": " + line)}}}}
  • 45. for loop: filters & nested loopsdef content(f: File): Seq[String] = ???for {file <- filesif !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. def content(f: File): Seq[String] = ???val lines = for {file <- filesif !file.getName.startsWith(".")line <- content(file)if line.nonEmpty} yield file + ": " + linefiles withFilter (!_.getName.startsWith(".")) flatMap { file =>content(file) withFilter (_.nonEmpty) map { line =>file + ": " + line}}for loop: filters & nested loops
  • 47. for loop: pattern matchingval Email = """(w+)@([w.]+)""".rdef emails(strs: String*) =for (Email(name, domain) <- strs) yield (name, domain)emails("foo@bar.com", "qwerty", "q@q.ru")// Seq[(String,String)] = ArrayBuffer((foo,bar.com),(q,q.ru))
  • 48. Basic Haskell - Scala dictionaryHaskell Scalax :: a, T a, [a] x : A, T[A], List[A]x : xs, [1,2], [1..n] x :: xs, List(1,2), 1 to ntail xs, map f xs xs.tail, xs map fa -> b -> c (A, B) => C | A => B => Cx -> x * sin x x => x * sin(x)Maybe |Just | Nothing Option | Some | Nonea >>= b, fmap, join a flatMap b, map, flattendo{ a<-x; b<-y; return c } for (a<-x; b<-y) yield c
  • 49. Parallelism & concurrencyval people: Seq[Person] = ...val (minors, adults) = people partition (_.age < 18)
  • 50. Parallelism & concurrencyval people: Seq[Person] = ...val (minors, adults) = people.par partition (_.age < 18)
  • 51. 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 ! minorsWork ! adults}}
  • 52. Futures & promisesFuture● Хранилище для значения, которое будетполучено в будущем● Получение значение может бытьвыполнено асинхронно и не блокироватьпрограмму● Значение может не быть получено вовсе
  • 53. 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)}
  • 54. Combining futuresval usdQuote = future { connection.getCurrentValue(USD) }val chfQuote = future { connection.getCurrentValue(CHF) }val purchase = for {usd <- usdQuotechf <- chfQuoteif isProfitable(usd, chf)} yield connection.buy(amount, chf)purchase onSuccess {case _ => println(s"Purchased $amount CHF")}
  • 55. Promisesval p = promise[T}val f = p.futureval producer = future {val r = produceSomething()p success rcontinueDoingSomethingUnrelated()}val consumer = future {startDoingSomething()f onSuccess {case r => doSomethingWithResult(r)}}
  • 56. 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}
  • 57. Akka● Toolkit & runtime for building concurrent,distributed & fault tolerant applications● Actors● Remoting: location transparent● Supervision & monitoring● Software Transactional Memory● Dataflow concurrency
  • 58. ToolsIDEs: IDEA, Eclipse, NetBeans+ Emacs, vim, Sublime, TextMateBuilding: 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
  • 59. Libraries & frameworksDB query & access: Slick (LINQ-like)UI: ScalaFXText processing: parser combinators (stdlib)GPGPU: ScalaCL...and many others
  • 60. Excelsior: наш опыт● Оптимизирующий компилятор● Новое ядро, implemented from scratch● R&D "по-взрослому"
  • 61. Excelsior: наш опыт● Оптимизирующий компилятор● Новое ядро, implemented from scratch● R&D "по-взрослому"● Команда: ≤5 человек
  • 62. Excelsior: наш опыт● Оптимизирующий компилятор● Новое ядро, implemented from scratch● R&D "по-взрослому"● Команда: ≤5 человек○ 4 из них не знали Скалу
  • 63. Excelsior: наш опыт● Оптимизирующий компилятор● Новое ядро, implemented from scratch● R&D "по-взрослому"● Команда: ≤5 человек○ 4 из них не знали Скалу● Время: 1.5 года * 4 человек○ всё работает, релиз был в апреле 2013
  • 64. Excelsior: наш опыт● Оптимизирующий компилятор● Новое ядро, implemented from scratch● R&D "по-взрослому"● Команда: ≤5 человек○ 4 из них не знали Скалу● Время: 1.5 года * 4 человек○ всё работает, релиз был в апреле 2013○ это мировой рекорд
  • 65. Novosibirsk Scala Enthusiasts
  • 66. Q / A
  • 67. Q / A
  • 68. Immutable classes and objectsTODO
  • 69. 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 }}
  • 70. Scala CollectionsЗдесь картинка - иерархия классовTraversableOnce, Traversable, Iterable,Iterator, Seq, Set, MapSeq: IndexedSeq, Buffer; List, imm.Vector,Array, ListBuffer, ArrayBuffer, ...Set: HashSet, BitSet, TreeSetMap: HashMap, TreeMap, ListMapboth mutable & immutable
  • 71. Типы: иерархия- Картинка- Top & bottom types: Any, Nothing- Основные типы: primitives, Unit, tuples,functions, Option- Составные типы:A with B with ... { refinement }- Отношение соответствия типов <:- Тип определяет интерфейс
  • 72. Type variance: определениеПусть есть Foo[T], и A <: B (A != B).Есть три возможности:1. Foo[A] <: Foo[B] - Foo ковариантен по T2. Foo[B] <: Foo[A] - Foo контравариантен по T3. Иначе, Foo инвариантен по TВариантность задаётся при объявлении класса:class Foo[+T] / class Foo[-T] / class Foo[T]ко- / контра- / ин-
  • 73. Type variance: примерыtrait InChannel[+T] { def get: T }val in: InChannel[String] = ...val x = in.get // x: Stringval in2: InChannel[Any] = inval x2 = in2.get // x2: Anytrait OutChannel[-T] { def put(x: T) }val out: OutChannel[Any] = ...out.put(42)val out2: OutChannel[String] = outout2.put("hello")
  • 74. Type variance: контроль типовclass Cell[+T] { // covariantdef get: T // okdef put(x: T) // compilation error}class Cell[-T] { // contravariantdef get: T // compilation errordef put(x: T) // ok}class Cell[T] { // invariantdef get: T // okdef put(x: T) // ok}
  • 75. Type variance: ещё примерыtrait Function1[-T, +R] { // contravariant argument(s)def apply(x: T): R // covariant result}class List[+T] { // immutable collections are covariantdef head: Tdef tail: List[T]}class Array[T] { // mutable collections are invariantdef apply(idx: Int): Tdef update(idx: Int, x: T)}
  • 76. Параметризация: примерabstract class List[+A] {def head: Adef tail: List[A]def isEmpty: Boolean}final case class Cons[+A](val head: A, val tail: List[A])extends List[A] {def isEmpty = false}case object Nil extends List[Nothing] {def head = throw new NoSuchElementException("Nil.head")...}
  • 77. Upper & lower type boundsdef max[A <: Ordered[A]](xs: List[A]): A = ???val accounts: Ordered[Money] = ???max(accounts)abstract class List[+A] {def ++[B >: A](that: List[B]): List[B] = ???}val strs = List("foo", "bar")val nums = List(13, 27)val all = strs ++ nums // List[Any]
  • 78. Compound Typestrait Cloneable {def clone: Cloneable = ???}trait Resetable {def reset(): Unit}def cloneAndReset(obj: Cloneable with Resetable): Cloneable = {val cloned = obj.cloneobj.reset()cloned}
  • 79. Structural & dynamic typesTODO