Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Scala Programming Language

Scala Programming Language

Introduction to Scala for Java developers with a set of examples.
Motivating to use Scala as the replacement for Java.

Vladimir Uspensky

February 26, 2014
Tweet

More Decks by Vladimir Uspensky

Other Decks in Programming

Transcript

  1. "If I were to pick a language to use today

    other than Java, it would be Scala“ James Gosling
  2. "I can honestly say if someone had shown me the

    Programming in Scala book by Martin Odersky, Lex Spoon & Bill Venners back in 2003 I’d probably have never created Groovy.“ James Strachan
  3. – Язык программирования Scala Scala обобщает ООП и функциональное программирование,

    использует новые концепции, позволяющие писать меньше кода и делать его более понятным и безопасным
  4. – ™ Scala – язык программирования, созданный в 2004 году

    в лаборатории профессора Мартина Одерски в EPFL – Федеральной Технической Школе Лозанны (Швейцария) ™ Мартин известен тем, что разработал Generics для Java и создал эталонную реализацию компилятора javac для Sun ™ При создании generics он был ограничен обратной совместимостью с предыдущими версиями ™ Scala создана с нуля и поэтому более целостна и Историческая справка
  5. – Scala была создана, чтобы расти вместе с запросами пользователей:

    на каждом уровне абстракции должны использоваться одни и те же конструкции. Для этого Scala объединяет объектно- ориентированную и функциональную парадигмы, предоставляет механизмы создания составных типов и расширения уже существующих. При этом Scala – чисто объектно-ориентированный Scalable language
  6. – Чистое ООП ™ Каждое значение – объект ™ Каждая

    операция – вызов метода 4+5 == 4.+(5)
  7. Иерархия классов ™ Any – общий предок для всех классов

    ™ AnyVal – общий предок для всех примитивов ™ AnyRef – аналог Object ™ Null – экземпляр любого ссылочного типа ™ Nothing – экземпляр любого типа ™ Unit – аналог void (блок кода, не возвращающий значения)
  8. – ™ Вместо интерфейсов используются traits ™ Traits – интерфейсы

    с реализованными методами ™ Подмешивание trait к классу не означает, что класс является разновидностью базового (is-a), как это происходит при наследовании. Подмешивание означает, что класс получает дополнительный функционал ™ На основе trait’ов можно создавать составные типы ™ Traits позволяют лучше переиспользовать код без недостатков множественного наследования. Mixin Class Composition
  9. – Mixin Class Composition class Animal trait Philosophical { def

    philosophize() { Console.println("It ain't easy being "+ toString +"!") } } class Frog extends Animal with Philosophical { override def toString = "green" } val frog = new Frog(); frog.philosophize(); // It ain't easy being green! override – ключевое слово Точки с запятой в конце строк не обязательны
  10. – class MyBool(x: Boolean) { def and(that: MyBool): MyBool =

    if (x) that else this def or(that: MyBool): MyBool = if (x) this else that def negate: MyBool = new MyBool(!x) def not(x: MyBool) = x negate; // здесь ; обязательно def xor(x: MyBool, y: MyBool) = (x or y) and not(x and y) } Перегрузка операторов ™ В названиях методов можно использовать почти все спецсимволы (+, -, !, =, <, >, *, @) ™ Каждый метод, принимающий один параметр может использоваться как инфиксный оператор, а без параметров как постфиксный:
  11. – ™ Scala – статически типизированный язык ™ Но при

    этом совсем не обязательно везде указывать какие типы должны быть использованы ™ Мощная система вывода типов определяет большинство типов по использованию переменных: Вывод типов (Hindley-Milner) def foo(s: String) = s.length def bar(x, y) = foo(x) + y
  12. – ™ Scala – статически типизированный язык ™ Но при

    этом совсем не обязательно везде указывать какие типы должны быть использованы ™ Мощная система вывода типов определяет большинство типов по использованию переменных: Вывод типов (Hindley-Milner) def foo(s: String) = s.length def bar(x, y) = foo(x) + y Int
  13. – ™ Scala – статически типизированный язык ™ Но при

    этом совсем не обязательно везде указывать какие типы должны быть использованы ™ Мощная система вывода типов определяет большинство типов по использованию переменных: Вывод типов (Hindley-Milner) def foo(s: String) = s.length def bar(x, y) = foo(x) + y Int Int
  14. – ™ Scala – статически типизированный язык ™ Но при

    этом совсем не обязательно везде указывать какие типы должны быть использованы ™ Мощная система вывода типов определяет большинство типов по использованию переменных: Вывод типов (Hindley-Milner) def foo(s: String) = s.length def bar(x, y) = foo(x) + y Int Int Int
  15. – ™ Scala – статически типизированный язык ™ Но при

    этом совсем не обязательно везде указывать какие типы должны быть использованы ™ Мощная система вывода типов определяет большинство типов по использованию переменных: Вывод типов (Hindley-Milner) def foo(s: String) = s.length def bar(x, y) = foo(x) + y Int Int Int Int
  16. – ™ Функции – вычисления с данными ™ Что мешает

    производить вычисления с функциями? Замыкания (closures) def apply(list: List[Int], f: (Int => String)) = { for(item <- list) yield f(item) } val toStr: (Int => String) = (a => "str" + a.toString) Console.print(apply(List(1,2,3), toStr).mkString(", ")) // str1, str2, str3 ™ В Scala функции – объекты первого порядка – замыкания ™ Функции высшего порядка – функции над функциями
  17. – Синтаксис замыканий { (x: Int, y: Long) => x

    + y } Список аргументов Тело функции Может опускаться в некоторых случаях
  18. – Притча о замыканиях Как-то однажды знаменитый учитель Кх Ан

    вышел на прогулку с учеником Антоном. Надеясь разговорить учителя, Антон спросил: «Учитель, слыхал я, что объекты — очень хорошая штука — правда ли это?» Кх Ан посмотрел на ученика с жалостью в глазах и ответил: «Глупый ученик! Объекты — всего лишь замыкания для бедных.» Пристыженный Антон простился с учителем и вернулся в свою комнату, горя желанием как можно скорее изучить замыкания. Он внимательно прочитал все статьи из серии «Lambda: The Ultimate», и родственные им статьи, и написал небольшой интерпретатор Scheme с объектно-ориентированной системой, основанной на замыканиях. Он многому научился, и с нетерпением ждал случая сообщить учителю о своих успехах. Во время следующей прогулки с Кх Аном, Антон, пытаясь произвести хорошее впечатление, сказал: «Учитель, я прилежно изучил этот вопрос, и понимаю теперь, что объекты — воистину замыкания для бедных». Кх Ан в ответ ударил Антона палкой и воскликнул: «Когда же ты чему-то научишься? Замыкания — это объекты для бедных!» В эту секунду Антон обрел просветление.
  19. – Pattern matching value match { case 1 => "one"

    case "two" => 2 case y: Int => "scala.Int" } map.get(key) match { case Some(x) => "got " + x case None => "got nothing" } List(v1, v2) filter (_ %2 == 0) match { case List(value1, value2) => "a" case List(value) => "b" case _ => "c" } Благодаря набору типов нельзя забыть проверку на null!
  20. – Ещё примеры • Hello world • POJO • Возвращение

    множественных параметров из функции • for на стероидах • Анонимные классы и final • Seamless Big Integers • Управление ресурсами • Взаимодействие с Java
  21. – Hello world! object HelloWorld { def main(args: Array[String]) =

    { var greeting = "" for (i <- 0 until args.length) { greeting += (args(i) + " ") } if (args.length > 0) { greeting = greeting.substring(0, greeting.length - 1) } Console.println(greeting) } }
  22. – POJO в Java public class Complex { private int

    re, im; public Complex(int re, int im) { this.re = re; this.im = im; } public int getRe() { return re; } public void setRe(int re) { this.re = re; } public int getIm() { return im; } public void setIm(int im) { this.im = im; } } final Complex number = new Complex(1, 0); number.setIm(12);
  23. – POJO в Scala class Complex(var re: Int, var im:

    Int) val number = new Complex(1, 0) number.im = 12
  24. – Возвращение множественных параметров из функции public Pair<Long, T> getNextMeasure()

    { return Pair.of(System.currentTimeMillis(), rnd.nextInt(100)); } Pair<Long, T> measure = getNextMeasure(); Long time = measure.getFirst(); T value = measure.getSecond(); System.out.println(time + “ - ” + value); def getNextMeasure()=(System.currentTimeMillis, rnd.nextInt(100)) val (time, value) = getNextMeasure() Console.println(time + “ - ” + value) Java Scala
  25. – for на стероидах val product = for( a <-

    List(1, 2, 3); b <- List("a", "b", "c") ) yield (a, b) Console.print(product) // List((1,a),(1,b),(1,c),(2,a),(2,b),(2,c),(3,a),(3,b),(3,c)) ™ Вложенные циклы можно объединить в одну конструкцию (например, для обработки произведений множеств) ™ Ключевое слово yield возвращает результат для итерации ™ Нет привычного for(…; …; …): for(int i = 0; i < n; i++) ~ for(i <- 0 to n)
  26. – Анонимные классы и final final Cell<Integer> sum = new

    Cell<Integer>(0); final Object[] result = { null }; foreach(new Integer[] {1,2,3,4,5,6,7,8,9,10}, new XXX() { public void f(int x) { sum.setValue(sum.getValue() + x); result[0] = new Object(); } }); System.out.println(sum) // 55 System.out.println(result) // java.lang.Object@147c5fc Java
  27. – Анонимные классы и final var sum = 0 var

    result: Any = null Array(1,2,3,4,5,6,7,8,9,10).foreach({ x => sum += x; result = new Object() }) Console.println(sum) // 55 Console.println(result) // java.lang.Object@147c5fc Scala
  28. – Анонимные классы и final var result: String DBHelper.executeQuery( ConnectionPools.getRegisteredPool(Pools.STAT),

    “select * from txn2”, resultSet => { result = resultSet.getString(COLUMN_NAME) true }); Console.println(result) Scala
  29. – Seamless Big Integers object bigint extends Application { def

    factorial(n: BigInt): BigInt = if (n == 0) 1 else n * factorial(n-1) val f50 = factorial(50); println("50! = " + f50) val f49 = factorial(49); println("49! = " + f49) println("50!/49! = " + (f50 / f49)) } ™ Благодаря возможности перегружать операторы, работать с большими числами можно как с обычными примитивами:
  30. – Взаимодействие с Java import scala.collection.mutable.{Set => MutableSet} import java.util.{Set

    => JavaSet} import scala.collection.JavaConversions._ class GetGadgets(val storage: Storage, val ids: java.lang.Iterable[Id[Gadget]]) { def gadgets: MutableSet[Gadget] = storage.find(Gadget.ID, ids) def exec = gadgets.map({ g => g.view(false) }) } Storage storage = new Storage(); GetGadgets query = new GetGadgets(storage, Arrays.asList(1,2,3)); Set<GadgetView> result = query.exec(); Scala Java
  31. – Работа с Map object Maps { val colors =

    Map("red" -> 0xFF0000, "turquoise" -> 0x00FFFF, "black" -> 0x000000, "brown" -> 0x804000) def main(args: Array[String]) { for(name <- args) println( colors.get(name) match { case Some(code) => name + " has code: " + code case None => "Unknown color: " + name } ) } }
  32. – Работа с коллекциями Scala предоставляет операции для работы с

    коллекциями более высокого уровня возможные при использовании ФП. За счёт их использования количество кода радикально сокращается.
  33. – Иерархия коллекций Iterable Set Map Seq Array List Queue

    Stack Traversable scala.collection.mutable scala.collection.immutable Range
  34. – Литералы для коллекций val colors = Map("red" -> 0xFF0000,

    "turquoise" -> 0x00FFFF, "black" -> 0x000000, "orange" -> 0xFF8040, "brown" -> 0x804000) List Map Set val colors = List(0xFF0000, 0x00FFFF, 0xFF8040, 0x804000) val colors = Set(0xFF0000, 0x00FFFF, 0xFF8040, 0x804000)
  35. – Массивы инвариантны Object[] arr = new Integer[1]; arr[0] =

    "Hello, there!"; val arr: Array[Any] = new Array[Integer](1) arr(0) = "Hello, there!" Java Scala
  36. – Массивы инвариантны Object[] arr = new Integer[1]; arr[0] =

    "Hello, there!"; val arr: Array[Any] = new Array[Integer](1) arr(0) = "Hello, there!" error: type mismatch; found : Array[Integer] required: Array[Any] var arr: Array[Any] = new Array[Integer](1) Java Scala java.lang.ArrayStoreException: java.lang.String
  37. – Filter val good = objects.filter(o => value.equals(o.getProperty)) List<Type> goodObjects

    = new ArrayList<Type>(objects.size()); for(Type object : objects) { if(value.equals(object.getProperty())) { goodObjects.add(object); } } Java Scala Замыкание (Closure)
  38. – Find val good: Option[Type] = objects.find(o => criteria(o)) Type

    good = null; for(Type object : objects) { if(criteria(object)) { good = object; break; } } Java Scala Возможно ничего не найти!
  39. – Exists val exists: Boolean = objects.exists(o => predicate(o)) boolean

    exists = false; for(Type object : objects) { if(predicate(object)) { exists = true; break; } } Java Scala Нужно помнить кучу подробностей
  40. – Map val newObjects = objects.map(o => f(o.getProperty)) List<Type2> newObjects

    = new ArrayList<Type2>(objects.size()); for(Type object : objects) { newObjects.add( f(object.getProperty()) ); } Java Scala
  41. – Fold val sum = integers.foldLeft(0) { _ + _

    } int sum = 0; for(Integer i : integers) { sum += i; } Java Scala Mutable state!
  42. – Zip val zipped : List((T1,T2)) = objects.zip(otherObjects) List<Pair<T1,T2>> zipped

    = new ArrayList<Pair<T1,T2>>(); int size = Math.min(objects.size(), otherObjects.size()); for(int i = 0; i < size; i++) { zipped.add(Pair.of(objects.get(i), otherObjects.get(i))); } Java Scala
  43. – Сортировка val sorted = objects.sort((o1, o2) => o1 <

    o2) Collections.sort(objects, new Comparator<Type>() { @Override public int compare(Type t1, Type t2) { if(t1 < t2) return 1; else if(t1 > t2) return -1; else return 0; } }) Java Scala
  44. – Ещё плюшки val head = objects.head // Первый элемент

    val last = objects.last // Последний элемент val tail = objects.tail // Список без первого элемента val init = objects.init // Список без последнего элемента val distinctObjects = List(2,4,6,4,2).distinct // List(2, 4, 6) val partition = List(1,2,3,4,5).partition((n) => n%2 == 0) // (List(2, 4), List(1, 3, 5)) Console.println((0 to 10).count(_ % 2 == 0)) // 6 Array("a", "b", "c").foreach(Console.print) // abc
  45. – ™ В Scala 2.9 появятся параллельные коллекции полностью совместимые

    с существующими последовательными. Для их использования достаточно будет просто изменить реализацию ™ Параллельные коллекции будут балансировать нагрузку на ядра процессоров при выполнении операций ™ Выпуск 2.9 RC1 планируется в феврале 2011 ™ Полный рассказ о новых параллельных коллекциях: http://days2010.scala-lang.org/node/138/140 Параллельные коллекции
  46. – Generics Для определения Generics в Scala используются обозначения отличающиеся

    от Java. Однако главное их преимущество в большем функционале и свободе реализовать вещи невозможные в Java
  47. – ™ Используются квадратные скобки вместо угловых Для индексации массивов

    используются круглые скобки ™ <: вместо extends ™ >: вместо super ™ Вместо ? используется _ _ используется во многих местах от import до pattern matching Обозначения
  48. – ™ Если класс параметризован типом, то нельзя не указывать

    этот тип. В Java такое возможно для обратной совместимости. В Scala это помогает избегать ошибок! ™ Параметризация методов типами идёт между именем метода и списком аргументов, а не перед типом возвращаемого значения ™ Классы параметризуются аналогично Java. Если у класса есть агрументы, то тип указывается перед ними (как при параметризации метода) Особенности параметризации
  49. – Ограничения типов class UpperBoundClass[T <: AnyVal] class LowerBoundClass[T >:

    AnyVal] // val upperBound: UpperBoundClass[Any] = new UpperBoundClass[Any]() val lowerBound: LowerBoundClass[Any] = new LowerBoundClass[Any]() val upperBound2: UpperBoundClass[Int] = new UpperBoundClass[Int]() // val lowerBound2: LowerBoundClass[Int] = new LowerBoundClass[Int]() val lowerBound3: UpperBoundClass[AnyVal] = new UpperBoundClass[AnyVal]() val upperBound3: LowerBoundClass[AnyVal] = new LowerBoundClass[AnyVal]()
  50. – Вариантность class Base { Object get(ArrayList argument) throws Exception

    } Class Child extends Base { List get(List argument) throws RuntimeException } Class ChildsChild extends Child { ArrayList get(Object argument) throws NullPointerException } Изменение одного типа относительно изменения другого ковариантно контравариантно ковариантно
  51. – Вариантность по параметру class CovariantClass[+T] class ContravariantClass[-T] val covariant:

    CovariantClass[Any] = new CovariantClass[Any]() val contravariant: ContravariantClass[Any] = new ContravariantClass[Any]() val covariant2: CovariantClass[Any] = new CovariantClass[Int]() //val contravariant2: ContravariantClass[Any] = new ContravariantClass[Int]() //val covariant3: CovariantClass[Int] = new CovariantClass[Any]() val contravariant3: ContravariantClass[Int] = new ContravariantClass[Any]() Any – супер-класс Int => ContravariantClass[Int] – супер-класс ContravariantClass[Any] Int – подкласс Any => CovariantClass[Int] – подкласс CovariantClass[Any]
  52. – Высший порядок trait Monad[T[_]] { def unit[X](x: X): T[X]

    def lift[X,Y](f: X => T[Y]): (T[X] => T[Y]) } class ListMonad[X](list: List[X]) extends Monad[List] { def unit[X](x: X): List[X] = List(x) def lift[X,Y](f: X => List[Y]): (List[X] => List[Y]) = { (mx: List[X]) => mx.map(f).flatten } }
  53. – Библиотеки Для Scala уже есть достаточное количество библиотек, покрывающих

    основные нужды: web, ORM, тестирование. Эти библиотеки в полной мере используют возможности Scala по созданию предметно-ориентированных языков (DSL)
  54. – Actor model параллелизм class Ponger extends Actor { def

    act() { loop { react { case Ping => sender ! Pong case Stop => exit() } } } } Actor - основной объект Scala для параллельных вычислений. Actor представляет собой объект, который общается со внешним миром путём обмена сообщениями
  55. – Akka class HelloWorldActor extends Actor { def receive =

    { case msg => self reply (msg + " World") } } RemoteNode.start("localhost", 9999) .register("hello-service", actorOf[HelloWorldActor]) // client code val actor = RemoteClient.actorFor("hello-service", "localhost", 9999) val result = actor !! "Hello" Actors могут быть использованы для реализации Comet, как обработчики Camel и для организации кластера
  56. – Parser combinators object SimpleScala extends RegexpParsers { val ID

    = """[a-zA-Z]([a-zA-Z0-9]|_[a-zA-Z0-9])*"""r val NUM = """[1-9][0-9]*"""r def program = clazz* def clazz = classPrefix ~ opt(classExt) ~ "{" ~ (member*) ~ "}“ def classPrefix = "class" ~ ID ~ "(" ~ formals ~ ")" def classExt = "extends" ~ ID ~ "(" ~ expr* ~ ")" def formals = repsep(ID ~ ":" ~ ID, ",") def member = ( ("val" | "var") ~ ID ~ ":" ~ ID ~ "=" ~ expr | "def" ~ ID ~ opt("(" ~ formals ~ ")“) ~ ":" ~ ID ~ "=" ~ expr ) def expr: Parser[Expr] = factor ~ ("+" ~ factor | "-" ~ factor)* def factor = term ~ ("." ~ ID ~ "(" ~ expr* ~ ")")* def term = ("(" ~ expr ~ ")" | ID | NUM ) }
  57. – Circumflex Web class Main extends RequestRouter { get("/") =

    "Hello world!" get("/posts/:id") = "Post #" + uri("id") post("/form") = { // Обработать запрос // . . . // Отрисовать шаблон FreeMarker: ftl("/done.ftl") } }
  58. – Circumflex ORM // Подготовим отношения, участвующие в запросах: val

    ci = City as "ci" val co = Country as "co" // Выбирает все русские города, возвращает Seq[City]: SELECT (ci.*) FROM (ci JOIN co) WHERE (co.code LIKE "ru") ORDER_BY (ci.name ASC) list // Выбирает страны с подходящими городами, возвращает Seq[(Country, City)]: SELECT (co.*, ci.*) FROM (co JOIN ci) list // Выбирает страны с количеством городов, возвращает Seq[(Country, Int)]: SELECT (co.*, COUNT(ci.id)) FROM (co JOIN ci) GROUP_BY (co.*) list
  59. – Specs "PersistentQueue" should { "add one item" in {

    withTempFolder { val q = new PersistentQueue(folder, "work", Config.empty) q.setup q.bytes mustEqual 0; q.journalSize mustEqual 0 q.add("hello kitty".getBytes) q.bytes mustEqual 11; q.journalSize mustEqual 32 q.close; dumpJournal("work") mustEqual "add(11:0:hello kitty)" } } }
  60. – ™ Scala компилируется в байт-код и работает на JVM

    ™ Возможно прямое взаимодействие с кодом на Java – Вызов кода на Java из Scala – И вызов кода на Scala из Java ™ Поддержка Scala есть в IntelliJ IDEA, Eclipse и NetBeans – IntelliJ IDEA 10.0.1 ловит некоторые ошибки только во время компиляции, а не во время набора кода, обещают исправить – IntelliJ IDEA умеет конвертировать код на Java в Scala ™ Для Scala есть библиотеки + есть возможность использовать все Java библиотеки Scala поддерживается
  61. – ™ LinkedIn ™ EDF (Électricité de France) ™ Twitter

    ™ Novell ™ Sony ™ Siemens ™ Xerox ™ FourSquare ™ The Guardian ™ GridGain Крупные компании и стартапы используют Scala «We're using Scala for real work in a business critical situation and there is a lot of money at stake if we get it wrong. There are risks, but we have had no problems [with Scala]. For me, a developer working at the coal face, the productivity improvements are massive.» Lee Momtahan. Électricité de France Trading.
  62. – ™ www.scala-lang.org ™ www.codecommit.com/blog/category/scala ™ http://bit.ly/vF6E3 ™ http://bit.ly/xZZt ™

    http://bit.ly/4TaXo ™ www.scala-lang.org/api/current/index.html ™ www.rsdn.ru/article/philosophy/Scala.xml ™ stackoverflow.com/questions/tagged/scala Дальнейшее чтение