Месяца назад я получил свою первую работу и стал стажер-разработчиком, наша команда использует язык Scala. Мне кажется, все начинающие разработчики в первый день потерянные. одновременно наваливается куча новых имен, технологий, каких-то правил, да и мало ли что еще, абсолютно все для тебя ново, это же первая работа. В моем же случае я еще и не знал языка, на котором буду программировать, до момента собеседования я даже никогда о нем не слышал. Итог: в первый день я был в полном ауте. Спросите как тогда я вообще получил эту работу? Я знал Java, на собеседовании мне сказали что джависту перейти на скалу будет достаточно легко и можно не переживать. Но видимо чуть-чуть попереживать все же стоило, потому что первое время перед собой я видел просто экраны, заполненные текстом, в которых сходу была ясна едва ли половина.

Но больше дискомфорта приносило даже не то, что я чего-то не понимал, а то что там многое по-другому, да даже тип переменной идет после названия, а порой его вообще нет.

final String str = "abc"; //Java

val str = "abc" // Scala

Вот так описывается функция:

int sum(int a, int b) {return a+b;} // Java

def sum(a: Int, b: Int) = {a + b} // Scala

А еще у Scala есть консоль REPL(Read-eval-print-loop), как, например, в Python. Как вы уже заметили пропали точки с запятой. Можно запускать одностраничные программы без main'а, названия методов и переменных могут содержать и начинаться вообще с любых символов, никаких правил. Там не static, но есть Object, там примитивы тоже объекты, == там на самом деле equals. Если у метода нет параметров то не обязательно ставить точку для вызова метода, скобки тоже опциональны если нет параметров, а если принимает только 1 параметр, то можно написать вот так:

str.charAt(5); // Java

str charAt 5 // Scala

И еще один интересный пример:

val res = 1 + 1

Нет, это не просто 1 плюс 1, здесь у объекта 1, вызывается метод + и ему передается единственным параметром объект 1. Для меня этого было разрывом шаблона.

На помощь моему шоку пришла замечательная книга Дэвида Поллака — Beginning Scala. Книга начинается с одной фразы, после которой я понял что обязательно должен дочитать ее до конца:
Ouch! That hurts my brain! Stop making me think differently. Oh, wait… it hurts less now. I get it. This different way of solving the problem has some benefits. I felt that way after my first year of law school. I felt that way for a while when I began coding Scala.
Дэвид имеет колоссальный опыт в программировании, начинал он это дело еще за 20 лет до моего рождения, успел поработать с более чем 10 языками программирования, пока не пришел к Scala. И теперь он говорит:
Scala is a programming language that provides a best-of-all-worlds experience for developers.
Тем не менее автор честно предупреждает, что овладеть им не так уж просто, ему для этого потребовалось 2 года, но он надеется, что мы сможем быстрее и он в этом поможет. Это не очень-то простая книга и она предполагает определенный опыт в программировании у читателя. Особенно она понравится тем, кто раньше программировал на Java, т.к. встречается много отсылок к этому языку и можно сравнивать.

Помимо Beginning Scala параллельно я читал уроки Twitter’s Scala School, для всех уроков есть перевод на русский язык, книгу Дэвида Поллака же удалось найти только в английском варианте.

Закрепить теорию помимо самостоятельных путешествий по исходникам скалы и работы помогал проект Scala Exercises, там очень простые задания, но вполне подходят для закрепления какого-то аспекта на первых порах и проверки того, что ты все внимательно прочитал и понял действительно правильно.

И расскажу немного про самые распространенные и очень простые вещи, которые пришлось постичь в первую очередь.

Option. В двух словах — это контейнер в котором либо пусто(None, похоже на null, но имеет методы map, filter, ...), либо лежит какое-то ровно одно значение Some(value) и его использование может сделать код более безопасным и не кидающим NullPointerException, потому что хочешь не хочешь, а чистые данные из Option нужно еще извлечь, и вот в этот момент забыть написать проверку уже сложно.
Конечно, у Option есть метод get, но использовать его не рекомендуется потому что в этом случае теряется весь смысл Option, т.к. None.get вызывает исключение.
Несколько самых очевидных удобств:

Легко возвращать значение по умолчанию в случае пустого Option

optValue.getOrElse(defaultValue)

В случае каких-то действий:

optValue match {
      case Some(value) => action
      case None => defaultAction
}

Пример из Scala Beginning. Путь есть некая база данных, которая содержит записи типы Person

def findPerson(key: Int): Option[Person]

Метод вернет Some[Person] если такая запись будет найдена и None иначе.
Теперь мы хотим получать возраст пользователя по ключу.

def ageFromKey(key: Int): Option[Int] = findPerson(key).map(_.age)

Нам не пришлось тестировать на None и метод получился очень лаконичным.

Pattern matching. В начале я подумал, что это тот же джавовский switch и использовать я его почти не буду, но это не так. В Scala это одна из самых часто используемых конструкций.

Приведение типов:


obj match {
      case str: String => str
      case number: Int => number
}

Можно добавить дополнительные условия и добавить действие по умолчанию


obj match {
      case strWithA: String if strWithA.contains("a") => strWithA
      case negative: Int if negative < 0 => negative
      case zero if zero == 0 => zero
      case _ => defaultAction
}

Крайне удобно использовать pattern-matching с case-классами. Пример из Scala Beginning


Stuff("David", 45) match {
      case Stuff("David", age) if age < 30 => "young David" 
      case Stuff("David", _) => "old David"
      case _ => "Other"
}

Функции

Начнем с того, что в Scala функции — это инстансы, реализующие определенный интерфейс, а точнее trait FunctionX, где X это количество параметров и принимает значение от 1 до 22. В этом трейте единственный метод — aplly, который и вызывается для функции. Поскольку функции это обычные инстансы, то мы можем передавать и возвращать их из методов и функций.
Пример из Scala Beginning. Передаем в answer какую-то функцию из Int в String, а она возвращает результат работы этой функции с параметром 42.


def answer(f: Function1[Int, String]) = f(42)

или что тоже самое


def answer(f: Function1[Int, String]) = f.apply(42)

Очень удобная вещь функциональные комбинаторы/

Оставить в массиве только положительные элементы:


arr.filter(value => value > 0)

Чуть более сложный пример. Посчитать сумму значений функции f от положительных элементов списка. 2 способа это сделать:


list.filter(x => x > 0).foldLeft(0)(_ + f(_))
list.filter(x => x > 0).map(f).sum

А в конце хотелось бы сказать зачем вообще я все это написал. Я не хотел никого учить Scala или рассказывать о языке как о таковом, таких статей на хабре и в интернете достаточно много, и многие очень хорошие и полезные. Моей целью было просто рассказать свою историю, которая кому-то может быть интересна и сможет помочь и поддержать какого-нибудь такого же потерянного новичка, которого судьба только-только столкнула с этой скалой. Желаю тебе удачи! Опытных же программистов призываю поделиться в комментариях своими советами и мнениями, на счет пути начинающего Scala-программиста.

Комментарии (39)


  1. freezlite
    06.04.2019 01:42

    Извините, но именования переменных и функций не очень то сбивающе с толку выглядит


  1. Focushift
    06.04.2019 02:26

    Чтото это мне напоминает… слабую типизацию в JS и другие «нюансы».
    Но JS принято хаять, а тут прям как манна небесная все эти возможности запутать код.


    1. arilou_camper
      06.04.2019 05:02

      В Scala это все compile time магия


    1. vchslv13
      06.04.2019 05:22

      Кто Вам сказал, что она слабая? Я не знаю Scala, но судя по Вики и моему знакомству с Хаскелем, типизация у Scala как-раз таки строгая статическая с выводом типов.


      1. Focushift
        06.04.2019 13:17

        Т.е. вот это правильно и все так должны делать?

        str charAt 5

        Пример повышенной читабельности


        1. stuf4ik
          06.04.2019 15:36

          Чтото это мне напоминает… слабую типизацию в JS и другие «нюансы»

          Scala является strong static type языком. За механизм вывода типа отвечает компилятор, если вы не указываете его явно.

          Т.е. вот это правильно и все так должны делать?

          Все зависит от вашего style guide. Но обычно такой вызов метода, в infix notation, не используется. Предпочитают более явный: str.charAt(5)


          1. olexandr17
            06.04.2019 16:16

            тогда и 1+1 можно писать, как 1.+(1)
            я изучал скалу полторы недели и да, некоторые шаблоны мышления успели порваться )


        1. borv
          06.04.2019 18:23
          +1

          Эта форма используется часто для DSL. В скале это одна из киллер фич. Вы описываете свои операторы для своего языка который вам подходит, получаете максимально выразительный код практически без boilerplate. Не все, конечно, ложится, но для всяких систем правил, ETL и прочего — очень удобно. Когда вы пишете просто императивный код есть соглашение, что когда есть символьные имена используется операторная нотация, а когда нет — обычная через "точку".


  1. javax
    06.04.2019 07:44
    +2

    В Java есть Optional, REPL и функции как инстансы. Сюрпрайз.

    А вообще — удачи!


    1. sshikov
      06.04.2019 09:36

      Собственно, после этого можно было не читать уже. Есть, и давно. Не говоря уже про то, что сторонние реализации Option существуют с момента появления generics.


      1. javax
        06.04.2019 09:38
        +5

        Давайте будем снисходительны. Джиниор, думал, что знает Джаву, открыл для себя Скалу, решил поделиться. Ну что плохого то? :)


        1. Optik
          06.04.2019 09:43
          +1

          От скалы тут тоже далеко не главное открыли.


          1. javax
            06.04.2019 09:46
            +2

            Откроет и монады :)
            Дайте ему время :)
            Учится, делится с остальными — молодец!


        1. sshikov
          06.04.2019 09:52
          +1

          Ну, особо плохого в том, чтобы чего-то не знать, конечно нет. Но понимать, что ты еще почти ничего не знаешь, вообще говоря стоит. У меня несколько двоякое впечатление — с одной стороны, явных ляпов нет, текст нормальный, а с другой — автор явно в глаза не видел Java 8 и новее.

          С точки зрения автора — все хорошо. С точки зрения читателя — еще один, сто десятый пост о том, что существует такая штука, как fold?


          1. sievmi Автор
            06.04.2019 10:43

            Конечно же я это прекрасно понимал, когда писал эту статью :) И мне казалось, явно это дал понять в ней, призывая опытных ребят делится советами с тем, кто только начинает.
            Вообще говоря, статью я писал 2 года назад и уже давно забыл про нее. Сейчас за нее немного стыдно)
            Но, тем не менее, главная цель — поделиться впечатлениями новичка и рассказать свою историю о том, как пробовал учиться. Для таких же новичков. Если бы я в то время нашел такую статью, мне было бы 100% интересно.


            1. sshikov
              06.04.2019 10:51
              +1

              А отчего же сейчас немного не переписать, если вы понимаете недостатки?


              1. sievmi Автор
                06.04.2019 11:03

                А зачем искажать впечатление? Тогда я думал и знал именно то, что написал. Если сейчас что-то исправлять, то получится уже рассказ совсем от другого человека. Что идет в разрез с тем, ради чего я ее тогда хотел написать.

                А про всякие технические неточности и т.п. уже написали, или напишут, в комментариях.

                Повторюсь, цель — рассказать историю. А переписывать историю не круто)


                1. sshikov
                  06.04.2019 11:44

                  Речь в общем не про переписывание истории, а про новый взгляд на историю из сегодняшнего дня. Это вполне могло бы быть интереснее.


        1. solver
          06.04.2019 12:41

          С одной стороны как бы да, вроде ничего плохого…
          А с другой стороны, такого материала просто завались в интернете.
          Он не добавляет вообще ничего к теме изучения, увеличивает данные при поиске инфы.
          Но самое главное! Такие статьи банально вводят в заблуждение неточностью информации. Что порождает чудовищное количество мифов во круг языков вообще и скалы в частности.
          Ведь никто не будет править статью, вносить изменения, уточнения и т.д. Она так и будет, извините, «засирать» головы начинающим разработчикам, у которых еще не сформировалось критическое мышление в отношении языков программирования.

          ИМХО Таким статьям место в личном бложике, а не на популярных ресурсах.


    1. Anton23
      06.04.2019 10:21

      А можно про REPL для Java поподробнее?


      1. ris58h
        06.04.2019 10:43

        JShell


  1. george3
    06.04.2019 09:11
    +1

    Главная фишка для простого программиста — ее Collections. Там есть immutable collections весьма полезные для параллельного и всякого другого программирования-моделирования где большие данные ветвятся на альтергативные варианты. Т е для реально чего-то сложного. Для обычных бизнес-приложений писать на Scala как ездить на танке в булочную. Прикольно но разницы с велосипедами-мопедами(Go, Kotlin,C#, Python, ..) особой нет.


    1. Optik
      06.04.2019 09:41
      +1

      1. Вот уж параллельные коллекции использовать не надо. Их выпилят в 2.13.
      2. Сравнение с танком странное. Если использовать как better-java, то разницы не особо — синтаксис и еще одно стдлиб. Если использовать фп, ну это как раз для бизнес-приложений отлично. Гарантий больше, тестов меньше.


      1. george3
        06.04.2019 11:24

        Про параллельные коллекции не заикался. А фп которое поверх коллекций весьма замедляет код, чем в тупую циклы как напр. на Go. Не умеют они их там умно разворачивать, а в новой 2.13 реализации как показывают тесты замены на VIEW варианты(которые там по умолчанию) еще замедляют а не ускоряют код. (P S Для меня Scala №1)


      1. fshp
        06.04.2019 23:17

        Их не выпилят, а вынесут в отдельный модуль.


  1. tuxi
    06.04.2019 12:00

    Option. Такого в Java нет. В двух словах — это контейнер в котором либо пусто(None, похоже на null, но имеет методы map, filter, ...),

    В java иногда (я первый раз в живом коде увидел в 2005 году) применяют паттерн создания статик инстанса объекта с именем NULL. И в методах, где возвращается экземпляр обьекта этого класса, если по ряду причин неудобно кидать эксепшен, возвращают этот NULL. Не всегда применимо, но частенько спасает. Особенно при всяких ETL операциях. Скала походу оттуда это взяла. Вкупе с паттерном «возвращать список» ваще сильно устойчивая ко всяким неожиданностям архитектура получается


    1. maxzh83
      06.04.2019 13:03

      применяют паттерн создания статик инстанса объекта с именем NULL

      Выглядит как царь-костыль.
      Скала походу оттуда это взяла.

      Маловероятно, в Scala много чего пришло из Haskell и других ФЯ. Посмотрите там Maybe, очень похоже. Ну а потом, уже видимо из Scala, это перекочевало в Java 8 в виде Optional.


      1. tuxi
        06.04.2019 13:30

        Любой паттерн применяемый везде, где надо и где не надо — станет царь-костылем

        Описанный мной паттерн удобно использовать, когда нужно замапить внешние данные в какую либо внутреннюю структуру и при этом нет большого смысла сообщать о нечастых ошибках во входных данных или о том, что незначительно изменилась их структура.
        Хотя бы потому, что никаких движений по их исправлению не будет, грубо говоря, заказчика вполне устраивает если будет успешно преобразовано 60..70% входных данных из большой иерархической структуры. Вот там такие «заглушки» вполне к месту.


      1. aleksandy
        06.04.2019 20:21
        +1

        Выглядит как царь-костыль.

        Вообще-то это довольно известны шаблон проектирования.


        1. maxzh83
          06.04.2019 20:29

          Как будто с помощью шаблона проектирования нельзя сделать костыль.


      1. fshp
        06.04.2019 23:30

        Костыль, костыль.
        None это синглтон типа Option[Nothing].
        Nothing это синтетический костыль-тип, являющийся подтипом для любого типа. Другими словами Nothing наследуется вообще от всего и сразу.
        Option ковариантен. А значит Option[Foo] является супертипом (родителем) для None: Option[Nothing].


        Именно ковариантность позволяет использовать None с Option любых типов.


        Благо все это существует лишь в разуме компилятора. А потом хренакс: привет стирание типов и Option[Object].


    1. den_po
      06.04.2019 15:40

      Ну совсем же не похоже — экземпляр класса vs пустая коллекция. Больше похоже на nullable объекты, только проверки на null легко потерять, а в Option/Optional тип хоть не совсем строго, но поощряет правильное использование.


      1. maxzh83
        06.04.2019 20:30

        Ну совсем же не похоже — экземпляр класса vs пустая коллекция.

        Не совсем понял, что не похоже? Где экземпляр класса? Где коллекция?


        1. den_po
          06.04.2019 22:45

          Экземпляр — NULL в комментарии tuxi, коллекция — Option.


          1. tuxi
            06.04.2019 23:20

            я спецом сразу написал в конце комментария

            Вкупе с паттерном «возвращать список» ваще сильно устойчивая ко всяким неожиданностям архитектура получается

            Речь про паттерн «всегда возвращаем список», то есть: нет результата — возвращаем пустой список.


  1. androidovshchik
    06.04.2019 12:54

    Я незнаком со Scala, но интересно, почему она в свое время не взлетела как Kotlin для андроида? По примерам из публикации лично у меня никакого дискомфорта нет и вроде как тоже меньше кода пишешь, удобнее


    1. maxzh83
      06.04.2019 13:10

      Очень тяжелая во всех смыслах. И для запуска на андроиде и для вхождения в язык широких масс, да и для тулинга тоже. Просто в статье много чего не описано, от этого кажется, что все просто. Посмотрите, например, на библиотеку scalaz, там все поинтереснее. Может возникнуть вопрос: а зачем мне эту дичь использовать? Ответ: вы может и не будете, но кто-то в вашей команде может. То есть, одну и ту же задачу в Скале можно решить множеством способом: и в стиле Java+ и в стиле Хаскеля. Это очень круто, но предъявляет повышенные требования к организации гайдов для кодинга и т.д.


  1. 0xd34df00d
    06.04.2019 15:53

    Scala is a programming language that provides a best-of-all-worlds experience for developers

    Понятно, что всяк кулик свое болото хвалит, но ровно это делает для меня скалу неюзабельной. Уж лучше императивное на плюсах, функциональщину на хаскеле или идрисе.


  1. fshp
    06.04.2019 23:20
    +1

    Нульарная Function0 смотрит на вас с обидой.