Scala
Upcoming SlideShare
Loading in...5
×
 

Scala

on

  • 643 views

 

Statistics

Views

Total Views
643
Views on SlideShare
501
Embed Views
142

Actions

Likes
0
Downloads
1
Comments
0

3 Embeds 142

http://devday.2gis.ru 114
http://devday.ru 27
http://devday2.2gis.test 1

Accessibility

Categories

Upload Details

Uploaded via as Adobe PDF

Usage Rights

© All Rights Reserved

Report content

Flagged as inappropriate Flag as inappropriate
Flag as inappropriate

Select your reason for flagging this presentation as inappropriate.

Cancel
  • Full Name Full Name Comment goes here.
    Are you sure you want to
    Your message goes here
    Processing…
Post Comment
Edit your comment

Scala Scala Presentation Transcript

  • def scala = oop + fpПавел Павлов
  • О себеЗанимаюсь системным программированием● компиляторы, среды исполнения● Excelsior JET - JVM with AOT compiler● код на орбите (ГЛОНАСС)Преподаю● научное руководство студентами (НГУ)● подготовка юниоров в компанииУчастник Scala community● Scala core committer (stdlib, compiler)● Организовал ScalaNsk
  • Язык Scala: характеристика● компилируемый● строго статически типизированный● автоматический вывод типов● OOP + FP● "лёгкий" синтаксис● работает на платформе JVM● бесшовная интеграция с Java
  • Язык Scala: цели● Язык общего назначения● Альтернатива/замена Java● Внедрение FP в mainstream● Преодоление "застоя" в OOPЦелевая аудитория:1. Java-программисты (народные массы)Лучший язык, FP2. Ruby/Python(/JS)-программистыСтатическая типизация, производительность3. ФункциональщикиИспользование FP в mainstream
  • Язык 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 matching1997-1998 Generic Javagenerics & javac compiler => Java language2001-2005 Scala 1.x"better than Java"2006- Scala 2.x2009-2010 Проникновение в индустрию
  • Язык Scala: популярность● 11 место - RedMonk Programming LanguageRankings (StackOverflow, GitHub)● 36 место - TIOBE index(поисковые запросы)
  • http://www.infoq.com/research/next-jvm-language
  • Success story: Twitter● 2006: начало - всё на Ruby on Rails● 2007-2008: взрывной рост популярности
  • Success story: Twitter● 2006: начало - всё на Ruby on Rails● 2007-2008: взрывной рост популярностиРешение:+
  • 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
  • Синтаксис: values & variablesval x: Int = 42val ys = List(1, 2, 3) // y: List[Int]var z = "hello" // z: String
  • Синтаксис: values & variablesval x: Int = 42val ys = List(1, 2, 3) // y: List[Int]var z = "hello" // z: Stringmake val not var
  • Синтаксис: 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
  • Синтаксис: основы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
  • 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")}Классы и объекты
  • 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: множественное наследованиес человеческим лицом
  • Scala = OOP + FPКак скрестить ужа с ежом?1. дешёвая китайская имитацияJava 8 lambdas2. мухи отдельно, котлеты отдельно3. кодируем объекты функциями4. кодируем функции объектами: Scala wayScala = OO kernel + syntactic sugar
  • Синтаксический сахар● бесскобочные методы● auto-generated accessors● операторы = методы,● операторный синтаксис● apply, update● for loop● case classes, unapply● implicitsДля чего? UAP, DSLs, extension methods, FP->OOP mapping, pattern matching
  • Uniform Access PrincipleВсе услуги, предлагаемые модулем должныбыть доступны через единую нотацию,которая не раскрывает, реализованы ли онипосредством хранения либо вычисления.Bertrand Meyer
  • 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
  • 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))
  • 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)!Вызов и индексация
  • Функциональные типы:(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)Функции как объекты
  • Case classes and pattern matching● Pattern matching - обобщённый switch/case● Case classes - реализация ADTПреимущества Scala:● Case class - больше чем ADT:интерфейсы, методы, данные● Pattern matching customizable by user:абстракция логики от структуры данных,DSLs
  • 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))}
  • 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"
  • 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"}
  • 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
  • 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)}
  • 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)
  • 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)
  • Types hierarchy
  • Типы● 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)
  • А также● mixin composition● implicits: extension methods, type classes● typesafe dependency injection● compound types● structural & dynamic types● delimited continuations● scala reflection● ...и многое другое
  • Internal DSLs
  • 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")
  • 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 poolsetc.)
  • for comprehension● обобщённый цикл for○ с поддержкой фильтров и pattern matching● преобразователь потоков данных● язык запросов● монадический комбинатор● всего лишь синтаксический сахар
  • 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 }
  • 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)}}}}
  • 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)}}
  • 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
  • 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))
  • 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
  • Parallelism & concurrencyval people: Seq[Person] = ...val (minors, adults) = people partition (_.age < 18)
  • Parallelism & concurrencyval people: Seq[Person] = ...val (minors, adults) = people.par partition (_.age < 18)
  • 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}}
  • Futures & promisesFuture● Хранилище для значения, которое будетполучено в будущем● Получение значение может бытьвыполнено асинхронно и не блокироватьпрограмму● Значение может не быть получено вовсе
  • 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)}
  • 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")}
  • 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)}}
  • 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}
  • Akka● Toolkit & runtime for building concurrent,distributed & fault tolerant applications● Actors● Remoting: location transparent● Supervision & monitoring● Software Transactional Memory● Dataflow concurrency
  • 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
  • Libraries & frameworksDB query & access: Slick (LINQ-like)UI: ScalaFXText processing: parser combinators (stdlib)GPGPU: ScalaCL...and many others
  • Excelsior: наш опыт● Оптимизирующий компилятор● Новое ядро, implemented from scratch● R&D "по-взрослому"
  • Excelsior: наш опыт● Оптимизирующий компилятор● Новое ядро, implemented from scratch● R&D "по-взрослому"● Команда: ≤5 человек
  • Excelsior: наш опыт● Оптимизирующий компилятор● Новое ядро, implemented from scratch● R&D "по-взрослому"● Команда: ≤5 человек○ 4 из них не знали Скалу
  • Excelsior: наш опыт● Оптимизирующий компилятор● Новое ядро, implemented from scratch● R&D "по-взрослому"● Команда: ≤5 человек○ 4 из них не знали Скалу● Время: 1.5 года * 4 человек○ всё работает, релиз был в апреле 2013
  • Excelsior: наш опыт● Оптимизирующий компилятор● Новое ядро, implemented from scratch● R&D "по-взрослому"● Команда: ≤5 человек○ 4 из них не знали Скалу● Время: 1.5 года * 4 человек○ всё работает, релиз был в апреле 2013○ это мировой рекорд
  • Novosibirsk Scala Enthusiasts
  • Q / A
  • Q / A
  • Immutable classes and objectsTODO
  • 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 }}
  • 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
  • Типы: иерархия- Картинка- Top & bottom types: Any, Nothing- Основные типы: primitives, Unit, tuples,functions, Option- Составные типы:A with B with ... { refinement }- Отношение соответствия типов <:- Тип определяет интерфейс
  • 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]ко- / контра- / ин-
  • 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")
  • 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}
  • 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)}
  • Параметризация: пример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")...}
  • 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]
  • Compound Typestrait Cloneable {def clone: Cloneable = ???}trait Resetable {def reset(): Unit}def cloneAndReset(obj: Cloneable with Resetable): Cloneable = {val cloned = obj.cloneobj.reset()cloned}
  • Structural & dynamic typesTODO