Зачем нужна Scala?

      Александр Казачёнок
Scala в двух словах



• Краткость кода как в Ruby

• Возможности IDE как в Java
Ruby или Java?
• Ruby
  меньше кода        => меньше багов

• Java
  умный компилятор   => меньше багов

• Scala
  меньше кода        => меньше багов
  умный компилятор   => меньше багов
Erlang или Java?
• Java быстрее.
  JVM быстрее Erlang VM.

• Erlang быстрее.
  Проще создавать мастштабируемые прил.

• Scala быстрее.
  JVM быстрее Erlang VM.
  Проще создавать мастштабируемые прил.
Мартин Одерски
•   Придумал Scala
•   Написал компилятор Scala
•   Написал компилятор Java
•   Соавтор Java generics


• Смешанные Scala+Java проекты в Eclipse, etc
• Microsoft спонсирует Scala.NET
• Компиляция в JavaScript с Google Web Toolkit
Джеймс Гослинг (создатель Java)
Джеймс Страчан (создатель Groovy)
Алекс Пейн (Twitter API Lead)
Scala в работе
Элитарность Scala
InfoQ: Тяжело ли найти разработчиков на Scala?
Дэвид Поллак:
   Нет. Найти хороших Scala разработчиков легко.
  Я могу организовать отличную команду из 10
  человек, готовую к работе на следующей неделе.
  Они не будут дешёвыми (средняя цена $250/час
  плюс то, что возьму я). Они не будут локальными.
  Но они будут отличными.
  Тяжело найти аутсорсовую команду из 25 Scala
  разработчиков за $40/час.
Количество фич в Scala
• Намного меньше, чем в C++ или C#
• Сравнимо с Java. Из Java удалены:
  static члены
  примитивные типы
  break и continue
  особое понятие об интерфейсах
  wildcard’ы
  raw типы
  enum’ы
• Фичи Scala более унифицированные и гибкие
Пример кода на Java
public class Person implements Serializable {
    private final String firstName;
    private final String lastName;

   public Person(String firstName, String lastName) {
       this.firstName = firstName;
       this.lastName = lastName;
   }

   public String getFirstName() {
       return firstName;
   }

   public String getLastName() {
       return lastName;
   }
Пример кода на Java (продолжение)
public Person withFirstName(String firstName) {
    return new Person(firstName, lastName);
}

public Person withLastName(String lastName) {
    return new Person(firstName, lastName);
}

public boolean equals(Object o) {
    if (this == o) {
        return true;
    }
    if (o == null || getClass() != o.getClass()) {
        return false;
    }
    Person person = (Person) o;
    if (firstName != null ? !firstName.equals(person.firstName)
                          : person.firstName != null) {
        return false;
    }
Пример кода на Java (продолжение)
        if (lastName != null ? !lastName.equals(person.lastName)
                             : person.lastName != null) {
            return false;
        }
        return true;
    }

    public int hashCode() {
        int result = firstName != null ? firstName.hashCode()
                                       : 0;
        result = 31 * result +
                 (lastName != null ? lastName.hashCode() : 0);
        return result;
    }

    public String toString() {
        return "Person(" + firstName + "," + lastName + ")";
    }
}
То же самое на Scala



case class Person(firstName: String, lastName: String)
Использование
• Java
     Person mr = new Person("Bob", "Dobbelina");
     Person miss = new Person("Roberta", "MacSweeney");
     Person mrs = miss.withLastName(mr.getLastName());


• Scala
     val mr = Person("Bob", "Dobbelina")
     val miss = Person("Roberta", "MacSweeney")
     val mrs = miss copy (lastName = mr.lastName)


     val mrs = miss.copy(lastName = mr.lastName)


     val mrs = miss.copy(miss.firstName, mr.lastName)
Коллекции

case class User(id: Int, userName: String)

val users: List[User] = // ....

val resultUsers = new ArrayBuffer[User]

for (i <- 0 until users.size) {
    if (users(i).userName != "test") {
        resultUsers += users(i)
    }
}
Коллекции
def formatUsers(users: List[User]): String = {
    val result = new StringBuilder
    for (i <- 0 until users.size) {
        val userName = users(i).userName
        if (userName != "test") {
            result.append(userName)
            if (i < users.size - 1) {
                 result.append(", “)
            }
        }
    }
    return result.toString
}
БАГ!



На предыдущем слайде есть баг :-(
filter

val resultUsers = users.filter(user => user.userName != "test")




val resultUsers = users filter (user => user.userName != "test")




val resultUsers = users filter (_.userName != "test")
map

val userNames = users map (_.userName)




val userNames = users map (user => user.userName)




val userNames = users.map(user => user.userName)
mkString


userNames.mkString(", “)




users map (_.userName) mkString ", "
formatUsers версия 2.0


def formatUsers(users: List[User]) =
    users map (_.userName) filter (_ != "test") mkString ", "



 •   Нет бага :-)
 •   Всего 3 шага
 •   Каждый шаг имеет смысл сам по себе
 •   Больше повторного использования кода
Повторное использование
• formatUsers версия 3.0

 def formatUsersInParallel(users: List[User]) =
     formatUsers(users.par)




• …
  ScalaCL => граф.карта => быстрее в 10-100
  раз
Java + Google Collections
public String formatUsers(final List<User> users) {
    final Collection<String> filteredUserNames = FluentIterable
      .from(users)
      .transform(new Function<User, String>() {
         @Override
         public String apply(final User user) {
           return user.getUserName();
         }
      })
      .filter(new Predicate<String>() {
         @Override
         public boolean apply(final String userName) {
           return !userName.equals("test");
         }
      })
      .toImmutableList();

     return Joiner.on(", ").join(filteredUserNames);
 }
Паттерны проектирования банды 4-х
• Написание повторно используемого кода
  на Java требует больших усилий
• На динамических языках и Scala многие из
  этих паттернов тривиальны
• Критика паттернов Питером Норвигом
  (директор по исследованиям в Google Inc.)
• ОО тоже когда-то было паттерном
Singleton


object Registry {
  def getEntry(): Entry = {
    // …
  }
  // …
}



val entry = Registry.getEntry
Strategy


def calculateTax(payer: TaxPayer,
                 strategy: TaxPayer => Double) = {
    strategy(payer)
}



calculateTax(employee, _.salary * 0.3)
Factory

object Car {
  def apply(type: String) = {
    type match {
      case “Race"   => new RaceCar
      case "Normal" => new NormalCar
      case _        => throw new Exception
    }
  }
}


val myCar = Car("Race“)
Visitor

trait Expr {
  //...
}

case class Var(value: Int) extends Expr
case class Sum(ex1: Expr, ex2: Expr) extends Expr

object EvalVisitor {
  def visit(expr: Expression) = expr match {
    case (Var(v)) => v
    case (Sum(e1, e2)) => visit(e1) + visit(e2)
  }
}
Decorator
trait Reader {
  type T
  def read: T
}

trait BufferedReader extends Reader {
  abstract override def read: T = {
    // ... buffering code
    super.read
  }
}

class FileReader extends Reader {
  type T = Char
  def read: Char = // ... Read somehow
}


val bufferedReader = new FileReader with BufferedReader
ОО + ФП = Scala
•       Объектная ориентация
    -     Любое значение – объект
    -     Любое действие – вызов метода у объекта
•       Функциональная ориентация
    -     Любое действие – вызов функции
    -     Любая функция – значение, которое можно присвоить
          переменной или передать другой функции
•       Scala
    -     Любое значение – объект
    -     Любое действие – вызов метода у объекта
    -     Любой метод – функция
    -     Любая функция – объект
Чистое функциональное прог-ание
•       Результат любой функции зависит только от
        входных параметров
•       Любая функция только возвращает результат
•       А это значит, что напрямую нельзя:
    -     Менять значения переменных
    -     Модифицировать структуры данных
    -     Менять поля объектов
    -     Бросать исключения
    -     Печатать на консоль и читать с неё
    -     Читать или писать в файл
    -     Рисовать на экране
Работе со строками
• В Java – функциональный подход
• В Ruby – не функциональный подход
Сравним
def formatUsers(users: List[User]) =
    users map (_.userName) filter (_ != "test") mkString ", "



def formatUsers(users: List[User]): String = {
    val result = new StringBuilder
    for (i <- 0 until users.size) {
        val userName = users(i).userName
        if (userName != "test") {
            result.append(userName)
            if (i < users.size - 1) {
                result.append(", “)
            }
        }
    }
    return result.toString
}
Преимущества ФП
• Части кода не зависят друг от друга
• Код более понятный
• Меньше багов
• Проще параллелизовать
• Проще оптимизировать компилятору

Недостатки ФП
• Иногда больше расход ресурсов
• Иногда сложнее написать
• Иногда невозможно написать
kazachonak.com
Скоро:
• Функциональное реактивное
   программирование в браузере на Scala
• По аналогии с
   KnockoutJS, EmberJS, JavaFX, C# Rx
Изучение Scala
• Уже 27 книг
• Бесплатные книги:
  – Scala for the Impatient
                                     Cay Horstmann
  – Programming in Scala
             Martin Odersky, Lex Spoon, Bill Venners
  – Programming Scala
                         Alex Payne, Dean Wampler
• Статья для Java’истов: Scala for Java Refugees
Scala IDE
•   Коммандная строка Scala REPL
•   Eclipse
•   IntelliJ IDEA
•   NetBeans
•   Emacs
•   TextMate
•   …
•   Kojo – развлекательная Scala для детей
Вопросы?

Зачем нужна Scala?

  • 1.
    Зачем нужна Scala? Александр Казачёнок
  • 2.
    Scala в двухсловах • Краткость кода как в Ruby • Возможности IDE как в Java
  • 3.
    Ruby или Java? •Ruby меньше кода => меньше багов • Java умный компилятор => меньше багов • Scala меньше кода => меньше багов умный компилятор => меньше багов
  • 4.
    Erlang или Java? •Java быстрее. JVM быстрее Erlang VM. • Erlang быстрее. Проще создавать мастштабируемые прил. • Scala быстрее. JVM быстрее Erlang VM. Проще создавать мастштабируемые прил.
  • 5.
    Мартин Одерски • Придумал Scala • Написал компилятор Scala • Написал компилятор Java • Соавтор Java generics • Смешанные Scala+Java проекты в Eclipse, etc • Microsoft спонсирует Scala.NET • Компиляция в JavaScript с Google Web Toolkit
  • 6.
  • 7.
  • 8.
  • 9.
  • 10.
    Элитарность Scala InfoQ: Тяжелоли найти разработчиков на Scala? Дэвид Поллак: Нет. Найти хороших Scala разработчиков легко. Я могу организовать отличную команду из 10 человек, готовую к работе на следующей неделе. Они не будут дешёвыми (средняя цена $250/час плюс то, что возьму я). Они не будут локальными. Но они будут отличными. Тяжело найти аутсорсовую команду из 25 Scala разработчиков за $40/час.
  • 11.
    Количество фич вScala • Намного меньше, чем в C++ или C# • Сравнимо с Java. Из Java удалены: static члены примитивные типы break и continue особое понятие об интерфейсах wildcard’ы raw типы enum’ы • Фичи Scala более унифицированные и гибкие
  • 12.
    Пример кода наJava public class Person implements Serializable { private final String firstName; private final String lastName; public Person(String firstName, String lastName) { this.firstName = firstName; this.lastName = lastName; } public String getFirstName() { return firstName; } public String getLastName() { return lastName; }
  • 13.
    Пример кода наJava (продолжение) public Person withFirstName(String firstName) { return new Person(firstName, lastName); } public Person withLastName(String lastName) { return new Person(firstName, lastName); } public boolean equals(Object o) { if (this == o) { return true; } if (o == null || getClass() != o.getClass()) { return false; } Person person = (Person) o; if (firstName != null ? !firstName.equals(person.firstName) : person.firstName != null) { return false; }
  • 14.
    Пример кода наJava (продолжение) if (lastName != null ? !lastName.equals(person.lastName) : person.lastName != null) { return false; } return true; } public int hashCode() { int result = firstName != null ? firstName.hashCode() : 0; result = 31 * result + (lastName != null ? lastName.hashCode() : 0); return result; } public String toString() { return "Person(" + firstName + "," + lastName + ")"; } }
  • 15.
    То же самоена Scala case class Person(firstName: String, lastName: String)
  • 16.
    Использование • Java Person mr = new Person("Bob", "Dobbelina"); Person miss = new Person("Roberta", "MacSweeney"); Person mrs = miss.withLastName(mr.getLastName()); • Scala val mr = Person("Bob", "Dobbelina") val miss = Person("Roberta", "MacSweeney") val mrs = miss copy (lastName = mr.lastName) val mrs = miss.copy(lastName = mr.lastName) val mrs = miss.copy(miss.firstName, mr.lastName)
  • 17.
    Коллекции case class User(id:Int, userName: String) val users: List[User] = // .... val resultUsers = new ArrayBuffer[User] for (i <- 0 until users.size) { if (users(i).userName != "test") { resultUsers += users(i) } }
  • 18.
    Коллекции def formatUsers(users: List[User]):String = { val result = new StringBuilder for (i <- 0 until users.size) { val userName = users(i).userName if (userName != "test") { result.append(userName) if (i < users.size - 1) { result.append(", “) } } } return result.toString }
  • 19.
  • 20.
    filter val resultUsers =users.filter(user => user.userName != "test") val resultUsers = users filter (user => user.userName != "test") val resultUsers = users filter (_.userName != "test")
  • 21.
    map val userNames =users map (_.userName) val userNames = users map (user => user.userName) val userNames = users.map(user => user.userName)
  • 22.
  • 23.
    formatUsers версия 2.0 defformatUsers(users: List[User]) = users map (_.userName) filter (_ != "test") mkString ", " • Нет бага :-) • Всего 3 шага • Каждый шаг имеет смысл сам по себе • Больше повторного использования кода
  • 24.
    Повторное использование • formatUsersверсия 3.0 def formatUsersInParallel(users: List[User]) = formatUsers(users.par) • … ScalaCL => граф.карта => быстрее в 10-100 раз
  • 25.
    Java + GoogleCollections public String formatUsers(final List<User> users) { final Collection<String> filteredUserNames = FluentIterable .from(users) .transform(new Function<User, String>() { @Override public String apply(final User user) { return user.getUserName(); } }) .filter(new Predicate<String>() { @Override public boolean apply(final String userName) { return !userName.equals("test"); } }) .toImmutableList(); return Joiner.on(", ").join(filteredUserNames); }
  • 26.
    Паттерны проектирования банды4-х • Написание повторно используемого кода на Java требует больших усилий • На динамических языках и Scala многие из этих паттернов тривиальны • Критика паттернов Питером Норвигом (директор по исследованиям в Google Inc.) • ОО тоже когда-то было паттерном
  • 27.
    Singleton object Registry { def getEntry(): Entry = { // … } // … } val entry = Registry.getEntry
  • 28.
    Strategy def calculateTax(payer: TaxPayer, strategy: TaxPayer => Double) = { strategy(payer) } calculateTax(employee, _.salary * 0.3)
  • 29.
    Factory object Car { def apply(type: String) = { type match { case “Race" => new RaceCar case "Normal" => new NormalCar case _ => throw new Exception } } } val myCar = Car("Race“)
  • 30.
    Visitor trait Expr { //... } case class Var(value: Int) extends Expr case class Sum(ex1: Expr, ex2: Expr) extends Expr object EvalVisitor { def visit(expr: Expression) = expr match { case (Var(v)) => v case (Sum(e1, e2)) => visit(e1) + visit(e2) } }
  • 31.
    Decorator trait Reader { type T def read: T } trait BufferedReader extends Reader { abstract override def read: T = { // ... buffering code super.read } } class FileReader extends Reader { type T = Char def read: Char = // ... Read somehow } val bufferedReader = new FileReader with BufferedReader
  • 32.
    ОО + ФП= Scala • Объектная ориентация - Любое значение – объект - Любое действие – вызов метода у объекта • Функциональная ориентация - Любое действие – вызов функции - Любая функция – значение, которое можно присвоить переменной или передать другой функции • Scala - Любое значение – объект - Любое действие – вызов метода у объекта - Любой метод – функция - Любая функция – объект
  • 33.
    Чистое функциональное прог-ание • Результат любой функции зависит только от входных параметров • Любая функция только возвращает результат • А это значит, что напрямую нельзя: - Менять значения переменных - Модифицировать структуры данных - Менять поля объектов - Бросать исключения - Печатать на консоль и читать с неё - Читать или писать в файл - Рисовать на экране
  • 34.
    Работе со строками •В Java – функциональный подход • В Ruby – не функциональный подход
  • 35.
    Сравним def formatUsers(users: List[User])= users map (_.userName) filter (_ != "test") mkString ", " def formatUsers(users: List[User]): String = { val result = new StringBuilder for (i <- 0 until users.size) { val userName = users(i).userName if (userName != "test") { result.append(userName) if (i < users.size - 1) { result.append(", “) } } } return result.toString }
  • 36.
    Преимущества ФП • Частикода не зависят друг от друга • Код более понятный • Меньше багов • Проще параллелизовать • Проще оптимизировать компилятору Недостатки ФП • Иногда больше расход ресурсов • Иногда сложнее написать • Иногда невозможно написать
  • 37.
    kazachonak.com Скоро: • Функциональное реактивное программирование в браузере на Scala • По аналогии с KnockoutJS, EmberJS, JavaFX, C# Rx
  • 38.
    Изучение Scala • Уже27 книг • Бесплатные книги: – Scala for the Impatient Cay Horstmann – Programming in Scala Martin Odersky, Lex Spoon, Bill Venners – Programming Scala Alex Payne, Dean Wampler • Статья для Java’истов: Scala for Java Refugees
  • 39.
    Scala IDE • Коммандная строка Scala REPL • Eclipse • IntelliJ IDEA • NetBeans • Emacs • TextMate • … • Kojo – развлекательная Scala для детей
  • 40.