No way back: Почему я перешел с Java на Scala и не собираюсь возвращаться

    Споры насчет преимуществ и недостатков Scala перед Java напоминают мне споры о C против С++. Плюсы, конечно же, на порядок более сложный язык с огромным количеством способов выстрелить себе в ногу, уронить приложение или написать совершенно нечитабельный код. Но, с другой стороны, C++ проще. Он позволяет делать простым то, что на голом C было бы сложно. В этой статье я попытаюсь рассказать о той стороне Scala, которая сделала этот язык промышленным — о том, что делает программирование проще, а исходный код понятнее.

    Дальнейшее сравнение между языками исходит из того, что читатель знаком со следующими вещами:

    — Java8. Без поддержки лямбд и говорить не о чем
    Lombok Короткие аннотации вместо длинных простыней геттеров, сеттеров, конструкторов и билдеров
    Guava Иммутабельные коллекции и трансформации
    Java Stream API
    — Приличный фреймворк для SQL, так что поддержка multiline strings не так и нужна
    flatMap — map, заменяющий элемент на произвольное количество (0, 1, n) других элементов.

    Иммутабельность по умолчанию


    Наверное, все уже согласны, что иммутабельные структуры данных — это Хорошая Идея. Scala позволяет писать иммутабельный код, не расставляя `final`

    Java
    @Value
    class Model {
        String s;
        int i;
    }
    public void method(final String a, final int b) {
      final String c = a + b;
    }
    


    Scala
    case class Model(s: String, i: Int)
    def method(a: String, b: Int): Unit = {
      val c: String = a + b
    }
    


    Блок кода, условие, switch являются выражением, а не оператором


    Т.е. всё вышеперечисленное возвращает значение, позволяя избавиться от оператора return и существенно упрощая код, работающий с иммутабельными данными или большим количеством лямбд.

    Java
    
    final String s;
    if (condition) {
      doSomething();
      s = "yes";
    } else {
      doSomethingElse();
      s = "no"
    }
    


    Scala
    val s = if (condition) {
      doSomething();
      "yes"
    } else {
      doSomethingElse();
      "no"
    }
    


    Pattern matching, unapply() и sealed class hierarchies


    Вы когда-нибудь хотели иметь switch, работающий с произвольными типами данных, выдающий предупреждение при компиляции, если он охватывает не все возможные случаи, а также умеющий делать выборки по сложным условиям, а не по полям объекта? В Scala он есть!

    Scala
      sealed trait Shape  //sealed trait - интерфейс, все реализации которого должны быть объявлены в этом файле
      case class Dot(x: Int, y: Int) extends Shape
      case class Circle(x: Int, y: Int, radius: Int) extends Shape
      case class Square(x1: Int, y1: Int, x2: Int, y2: Int) extends Shape
    
      val shape: Shape = getSomeShape() //объявляем локальную переменную типа Shape
    
      val description = shape match {
          //x и x в выражении ниже - это поля объекта Dot
        case Dot(x, y) => "dot(" + x + ", " + y + ")"
          //Circle, у которого радиус равен нулю. А также форматирование строк в стиле Scala
        case Circle(x, y, 0) => s"dot($x, $y)"
          //если радиус меньше 10
        case Circle(x, y, r) if r < 10 => s"smallCircle($x, $y, $r)"
        case Circle(x, y, radius) => s"circle($x, $y, $radius)"
          //а прямоугольник мы выбираем явно по типу
        case sq: Square => "random square: " + sq.toString
      } //если вдруг этот матч не охватывает все возможные значения, компилятор выдаст предупреждение
    


    Java
    Даже пытаться не буду повторить это на джаве.

    Набор синтаксических фич для поддержки композиции


    Если первыми тремя китами ООП являются (говорим хором) инкапсуляция, полиморфизм и наследование, а четвертым агрегация, то пятым китом, несомненно, станет композиция функций, лямбд и объектов.

    В чем тут проблема джавы? В круглых скобочках. Если не хочется писать однострочники, то при вызове метода с лямбдой придется заворачивать её дополнительно в круглые скобки вызова метода.

    Java
    
    //допустим у нас есть библиотека иммутабельных коллекций с методами map и flatMap. Для другой библиотеки коллекций это будет еще больше кода.
    //в collection заменить каждый элемент на ноль, один или несколько других элементов, вычисляемых по алгоритму
    collection.flatMap(e -> {
      return getReplacementList(e).map(e -> {
        int a = calc1(e);
        int b = calc2(e);
        return a + b;
      });
    });
    
    withLogging("my operation {} {}", a, b, () -> {
      //do something
    });
    


    Scala
    collection.flatMap { e =>
      getReplacementList(e).map { e =>
        val a = calc1(e)
        val b = calc2(e)
        a + b
      }
    }
    
    withLogging("my operation {} {}", a, b) {
      //do something
    }
    


    Разница может казаться незначительной, но при массовом использовании лямбд она становится существенной. Примерно как использование лямбд вместо inner classes. Конечно, это требует наличия соответствующих библиотек, рассчитанных на массовое использование лямбд — но они, несомненно, уже есть или скоро появятся.

    Параметры методов: именованные параметры и параметры по умолчанию


    Scala позволяет явно указывать названия аргументов при вызове методов, а также поддерживает значения аргументов по умолчанию. Вы когда-нибудь писали конверторы между доменными моделями? Вот так это выглядит в скале:

    Scala
    def convert(do: PersonDataObject): Person = {
      Person(
        firstName = do.name,
        lastName = do.surname,
        birthDate = do.birthDate,
        address = Address(
          city = do.address.cityShort,
          street = do.address.street
        )
      )  
    


    Набор параметров и их типы контролируются на этапе компиляции, в рантайме это просто вызов конструктора. В джаве же приходится использовать или вызов конструктора/фабричного метода (отсутствие контроля за аргументами, перепутал местами два строковых аргумента и привет), или билдеры (почти хорошо, но то, что при конструировании объекта были указаны все нужные параметры, можно проверить только в рантайме).

    null и NullPointerException


    Скаловский `Option` принципиально ничем не отличается от джавового `Optional`, но вышеперечисленные особенности делают работу с ним легкой и приятной, в то время как в джаве приходится прилагать определенные усилия. Программистам на скале не нужно заставлять себя избегать nullable полей — класс-обертка не менее удобен, чем null.

    Scala
    val value = optValue.getOrElse("no value") //значение или строка "no value"
    val value2 = optValue.getOrElse {  //значение или exception
      throw new RuntimeException("value is missing")
    }
    val optValue2 = optValue.map(v => "The " + v) //Option("The " + value)
    val optValue3 = optValue.map("The " + _) //то же самое, сокращенная форма
    val sumOpt = opt1.flatMap(v1 => opt2.map(v2 => v1 + v2)) //Option от суммы значений из двух других Option
    
    val valueStr = optValue match { //Option - это тоже sealed trait с двумя потомками!
    
      case Some(v) =>  //сделать что-то если есть значение, вернуть строку
        log.info("we got value {}", v)
        "value.toString is " + v
    
      case None => //сделать что-то если нет значения, вернуть другую строку
        log.info("we got no value")
        "no value"
    }
    


    Конечно же, этот список не полон. Более того, каждый пример может показаться незначащим — ну какая, в самом деле, разница, сколько скобочек придется написать при вызове лямбды? Но ключевое преимущество скалы — это код, который получается в результате комбинирования всего вышеперечисленного. Так java5 от java8 не очень отличается в плане синтаксиса, но набор мелких изменений делает разработку существенно проще, в том числе открывая новые возможности в архитектурном плане.

    Также эта статья не освещает другие мощные (и опасные) фичи языка, экосистему Scala и ФП в целом. И ничего не сказано о недостатках (у кого их нет...). Но я надеюсь, что джависты получат ответ на вопрос «Зачем нужна эта скала», а скалисты смогут лучше отстаивать честь своего языка в сетевых баталиях )
    AdBlock has stolen the banner, but banners are not teeth — they will be back

    More
    Ads

    Comments 131

      0

      А можете пояснить, как это switch выдает предупреждения, если внутри есть произвольные условия? Мне кажется это невозможно в общем случае. Вот смотрите:


      case Circle(x, y, r) if r < 10 => s"smallCircle($x, $y, $r)"
      case Circle(x, y, radius) => s"circle($x, $y, $radius)"


      замените тут 10 на переменную — и статический анализ этого кода компилятором станет невозможным.

        0

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

          0

          Ну, самый-то простой случай без статической проверки полноты уже вполне съедобен даже на Java 8 :) При наличии javaslang например. Выглядит кривовато, но не слишком.

            0

            Не слишком кривовато до тех пор, пока вы не пишете что-то уж очень завязанное на сообщения (akka)

              0

              Ну, да. Я бы даже сказал — до тех пор, пока не попробуете скомбинировать несколько таких switch в единое целое. В текущем проекте я довольно активно javaslang использую, и вполне себе заметно, что с нарастанием сложности оно регулярно ломается во вполне предсказуемом месте — на слабостях системы типов Java.

          0
          По моему, проверяется что все покрыто безусловными паттернами. Даже если условие в if не выполнится, найдется подходящий образец.
            0
            Увы, нет. На данный момент не проверяется никак.
            +1
            На самом деле никак: как только условия появляются, предупреждения не выдаются: https://issues.scala-lang.org/browse/SI-5365. Был pull request, чтобы переключиться на пессимистический вариант, но в 2.12.0 не попал (см. последний комментарий по ссылке).
            –27
            У Java и Scala разные ниши (Java — аутсорс, малый и местный бизнес, Scala — глобальные продуктовые компании), поэтому пофичечное сравнение не очень корректно.
            • UFO just landed and posted this here
                –9
                Scala — малый и местный бизнес? Действительно смешно… Про Scala в аутсорсе просто не верю… Значит это ниши Java ))
                Scala позволяет писать большие и сложные проекты ОДНОЙ командой быстрее, чем Java (хотя раньше за неимением такой альтернативы Java была практически монополистом). Поэтому продуктовая IT-контора. И глобальная потому что иначе и смысла нет напрягаться.

                Я не против минусов, но хотелось бы и доводы услышать…
                • UFO just landed and posted this here
                    0
                    Так мы же про ниши говорим, а не то, насколько их удается освоить.
                    • UFO just landed and posted this here
                        0

                        А Котлин в Польше. Нужно еще уметь анализировать цифры, а не верить им не понимая сути.

                        • UFO just landed and posted this here
                      0
                      Я работаю в небольшой компании (примерно 50 человек), в отделе, который разрабатывает облачную PLM-систему. Вполне себе средний бизнес. Практически все наши сервисы написаны на Scala.
                    +6

                    Как человек, видевший и стартапы на скале, и глобальные продуктовые компании на джаве, не соглашусь. Разве что Scala-аутсорс — это звучит странно.

                      –2
                      А разве «стартапы на скале» противоречат моему высказыванию? А «глобальные продуктовые компании на джаве» — это скорее след из прошлого…
                        +1

                        В таком случае я работаю в "следе из прошлого"

                          –2
                          Это у всех так. В будущее смотреть скорее надо для планирования.
                      +3

                      Вы посмотрите статистику продуктовых проектов на scala и на java и поймете, почему наминусили. А что "Java — аутсорс, малый и местный бизнес" это вообще трудно откоментировать так, чтобы не обидеть.

                        –1
                        Постарайтесь… Добавлю только, что про ниши я говорил в некоторой перспективе (думал, что и так понятно).
                    • UFO just landed and posted this here
                        0

                        Потому, что однострочники не масштабируются — при усложнении кода они становятся… ммм… менее читабельными. Пока лямбду можно уложить в поток стримов, это хорошо. А когда нужно будет её усложнить? Код на стримах придется переписывать.

                          0

                          Так или иначе, даже если писать однострочники, скала выиграет 2 строки :)

                          +3
                          читатель знаком со следующими вещами
                          Lombok
                          иммутабельный код
                          @Data
                          class Model {
                          private final String s;
                          private final int i;
                          }

                          Для immutable классов в Lombok-е используется @Value: https://projectlombok.org/features/Value.html


                          @Value
                          class Model {
                              String s;
                              int i;
                          }

                          дальше видимо можно не читать...

                            –3

                            Спасибо, сейчас поправлю :-) Два года на скале сказываются — начал подзабывать уже.

                            +11
                            Если это все что хочется от Скалы, то можно взять Котлин
                              +2
                              В Котлине таки сделали pattern matching?
                                +1
                                Того что уже есть в языке хватает.
                                  0

                                  Ещё нет, но в 1.1 обещали ограниченные продолжения и нормальную деструктуризацию, вот тогда будет как раз хватать :)

                                    0
                                    Речь была о control-flow.
                                    Ну и «продолжения» для меня диковато звучат. «Континуации» наверно не лучше, зато есть принятые «корутины». Так что да, будут Корутины в Котлин.
                              +9
                              Все эти Java vs Scala, Coffeescript vs Javascript итд к сожалению обычно заканчиваются печально для тех, кто выбирает молодые языки.

                              Рано или поздно под давлением комьюнити все нужные фичи появляются в базовых языках и через какое-то время конкуренты начинают умирать.

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

                              Вы не подумайте, что я считаю ее плохой — она действительно СЕЙЧАС удобнее Java. Но за долгие годы карьеры мне приходилось несколько раз ставить «не на ту лошадь», что выливалось в серьезные проблемы впоследствии.
                                +2

                                Вы правы, но я специально подобрал для статьи фичи, которые не так-то просто добавить в существующий синтаксис Java и существующую идеологию Java. К тому же, Java развивается ОЧЕНЬ медленно — оракл не может себе позволить добавить в язык что-то трендовое и не проверенное временем.


                                Если lightbend не разорится, на 5-10 лет активного развития языка рассчитывать можно.

                                  +2
                                  А дело не в том, можно или нет добавить какие-то фичи. Просто в какой-то момент «фич» Скала станет недостаточно, чтобы привлекать новых людей в комьюнити, и язык начнет умирать.
                                    +1
                                    Языковые фичи (синтаксический сахар) — это самый плохой повод выбирать тот или иной язык программирования.

                                    Вот, к примеру, Go — языковых фич в нем минимум! и это невероятно круто!
                                    Чем меньше фич, чем меньше долбанной магии под капотом — тем лучше будет проектироваться и работать вся система в целом.

                                    В java довольно много фич, действительно лишних фич: strictfp, assert, instanceOf, labels (да-да, типа таких как для goto). Если бы Оракл вводил все подряд на уровень языка — java уже давно умерла бы. Даже сейчас для новичком Java — это тяжелый язык (и платформа), если бы в ней было бы больше фич — этот язык был бы фактически неподъемным.
                                    • UFO just landed and posted this here
                                        +3
                                        instanceOf — плохой оператор в целом. Вариант через API на много лучше. НО!

                                        Я имел ввиду, что instanceOf — это в принципе устаревшая конструкция. С появлением дженериков в ней пропала необходимость.
                                        Если нужно завязать логику на конкретный тип — используйте либо дженерики, либо перегрузку методов.
                                        99% задач не требуют проверки типа. Тем более, это проверка не на конкретный тип, а на принадлежность иерархии.

                                        Единственная причина использовать instanceOf — это переопределение equals метода в иерархии классов. Но это в принципе плохой подход к построение архитектуры. Иерархия data-классов ни к чему хорошему еще не приводила, тем более с переопределенным equals.
                                        • UFO just landed and posted this here
                                            0
                                            Вообще-то я говорил, что instanceOf — это признак плохо спроектированного кода, а не дженерики.

                                            > Они не могут на 100% отменить необходимость в instanceOf

                                            Дженерики — не покрывают, это известный факт, но ведь еще есть и перегрузка методов.

                                            Был бы рад услышать пример, когда instanceOf действительно необходим, может я уперся в стену и не вижу всей картины.
                                            • UFO just landed and posted this here
                                                0
                                                С другой стороны reflection — это уже способ вылезти за приделы языка, не так ли?
                                                Код с рефлексией толком не оптимизаруется через jit.
                                                Теряется практически весь смысл строгой типизации — ошибок на этапе компиляции не будет (если не через annotation processing), зато будут проблемы в рантайме.

                                                Reflection — это не то, что стоит использовать повсеместно.

                                                А на счет instanceof, честно, не могу придумать примера для адекватного его использования, даже с дженериками — проверять параметризированный тип через instanceof?))

                                                ps: если перегрузка — это плохо для рефлексии, то если будут дефолтные параметры (вместе с перегрузкой) — можно будет сразу повеситься =)
                                                • UFO just landed and posted this here
                                                    –1
                                                    > и потом надо как-то получать его реальный тип.

                                                    В этой строчке кроется корень проблемы. Если вы передаете куда-то наследника какого-то класса, то по принципу Лисков (liskov substitution, L из SOLID) система должна будет работать так же.
                                                    Если вкратце, любой код, который принимает какой-то базовый класс не должен никоим образом завязываться на конкретную имплементацию этого базового класса.

                                                    Для сериализации instanceof не подойдет, как минимум перебирать все возможные типы данных — это глупо. Да и instanceof показывает принадлежность к целой иерархии типов, а не к конкретному классу. Для сериализации используют стандартную java сериализацию (Serializable или Externalizable) или Reflection API.
                                                    • UFO just landed and posted this here
                                                        –1
                                                        В текущем треде вы уже который раз перекручиваете мои слова.
                                                        Я говорил, что instanceof — плохо, дженерики — хорошо.

                                                        Вы перекрутили так, будто я говорил обратное. Не нужно так =)

                                                        На счет пайплайна.
                                                        Если ваши обработчики должны принимать какие-то решения в зависимости от того типа данных, который к ним приходит — просто заведите в интерфейсе какой-то Enum / EnumSet атрибут, по которому будете принимать решение. Это будет более явный и правильный подход к обработке, чем завязка на тип реализации.
                                                        • UFO just landed and posted this here
                                                            0
                                                            Не перекрутили, но смысл не полностью уловили.

                                                            Вместо того, чтобы завязываться на какой-то конкретный тип реализации вы будете завязываться на публичный API. Это идеологически разные подходы.
                                                            • UFO just landed and posted this here
                                                            0
                                                            Я говорил, что instanceof — плохо, дженерики — хорошо.

                                                            Но, подождите, в рефлекшене есть методы getClass, getSuperclass, getInterfaces. Что мешает мне руками написать instanceOf(Object, Class)?

                                                        • UFO just landed and posted this here
                                                            0
                                                            Это замечательный пример!

                                                            С instanceof вы проходите по всему списку подписчику и каждому даете сообщение на обработку (прям Chain of Responsibility), каждый уже сам решает обрабатывать ему или нет. Сложность обработки одного события O(N), где N — это общее количество всех подписчиков на все события.

                                                            И тут есть 2 кейса:
                                                            1. Вы хотите подписаться на конкретный тип события, никакие другие не хотите слушать.

                                                            Map<Class<? extends Event>, List<EventHandler<? extends Event>> handlers;
                                                            В этом случае вы можете использовать java.util.Map и сделать обработку за O(M),
                                                            где M — это количество обработчиков подписанных на конкретный тип сообщения (M ≤ N).

                                                            Плюсы:
                                                            — вы имеете строгую типизацию без проверок и приведения типов в рантайме.
                                                            — вы обрабатываете только те события, которые вам интересны (без лишних вызовов).

                                                            Минус:
                                                            — в этом простом примере вы теряете возможность подписаться на все дочерние события (подписаться на Event и получать вообще все события — не получится; но нужно ли это?).

                                                            2. Вы хотите подписаться на целую иерархию типов:
                                                            Event > MyEvent > MySuperEvent
                                                            — Вы подписываетесь на Event, и получаете вообще все события на обработку.

                                                            Этот кейс в безопасном виде решить будет сложнее:

                                                            Map<String, List<EventHandler<? extends Event>> handlers;
                                                            — вы подписываетесь на конкретное сообщение (String | Enum), и ожидаете, что тот, кто будет кидать сообщение с этим типом будет кидать его в нужном типе.

                                                            Плюс:
                                                            — Вы сохраняете возможность получать всю иерархию в ваш обработчик
                                                            — Вы по прежнему обрабатываете только те события, которые интересны
                                                            Минус:
                                                            — Теряется безопасность типов (в рантайме можно выхватить класс каст эксепшн)

                                                            Да, в этом случае instanceof обеспечил бы безопасность типов, но если кто-то унаследуется от вашего класса, и кинет сообщение, то вы будете обрабатывать события, которые не должны были обрабатывать и ошибка в этом случае не вывалится (а это еще хуже, чем сразу свалиться).

                                                            Зачем кому-то наследоваться от вашего события?
                                                            Да просто потому, что там есть такие же поля (для тех, кто не знает принципиальной разницы между Абстрактным классом и Интерфейсом — это нормально дело).
                                                      0
                                                      А зачем пользоваться рефлекшеном?
                                                        0
                                                        К примеру, чтобы обрабатывать аннотации.
                                                        На этапе компиляции можно по аннотациям сгенерировать дополнительные методы, обертки или кучу всяких классных (или не очень) вещей. Так делают lombok — позволяет уменьшить количество бойлерплейт кода; и mapstruct — маппер одних бинов на другие.

                                                        Так же в рантайме, для добавления гибкости. Spring, Hibernate, JPA, JAX-RS, Guice и множество других.

                                                        Или для написания фреймворков с контрактом именования методов. Spring Data, некоторые OSGi фреймворки, junit 3.x и много других.
                                                        • UFO just landed and posted this here
                                                        0
                                                        • рефлекшн. в частности, сериализация
                                                        • тот самый случай, когда проще написать instanceof чем добавлять методы в интерфейс/городить паттерн Визитор.
                                                    +2
                                                    По поводу меток тоже не сильно далеко все ушло.
                                                    Мекти в java есть только в двух операторах break и continue.
                                                    Предназначены, чтобы выйти из большой вложенности циклов.

                                                    Но ведь большая вложенность циклов — это уже плохо спроектированный код. А с метками этот код станет только хуже!
                                                    Но если так исторически сложилось и нужно досрочно выйти из большой вложенности циклов, можно же эти циклы обернуть в один метод и просто выйти из него через return. Это не сильно ударит по производительности, но код будет лучше читаться.

                                                    ps: я еще ни разу не встречал метки в реальных java проектах, зато видел много java разработчиков, которые даже не знают про их существование.
                                                    • UFO just landed and posted this here
                                                        –2
                                                        Наличие instanceOf делает Java (как и C#) лично мне на порядок удобнее — добавляет языкам некоторые свойства динамических при сохранении статического контроля типов где надо. Я не претендую на знатока языка, но в моем единственном проекте на Java половина типов — Object. Вот так незамысловато получаем динамическую типизацию, полиморфные контейнеры и вообще полную свободу действий. Вы скажете — что это овноархитектура и овнокот и что надо на дженериках/интерфейсах или что там еще? Но мне так гораздо удобнее.
                                                          0
                                                          Что ж, если вы строите решение на Object + instanceOf и говорите, что это удобно, возможно так оно и есть. Люди разные, кто-то на гвоздях спит, кто-то стекло есть, кто-то Object + instanceOf повсеместно использует. У каждого своя правда!

                                                          ps: тред про instanceOf был немного выше.
                                                            0
                                                            instanceof (в java) пишется в lowcase
                                                          +4

                                                          Не совсем понятно как большая вложенность циклов обязательно означает плохо спроектированный код. Есть много алгоритмов в которых никак не уйти от вложенных циклов. Можно конечно обернуть все вокруг в методы, постоянно проверять результаты их работы и т.д. но зачем городить лапшу, когда достаточно проставить break label.
                                                          Я не говорю что у меток широкий спектр применения, но иногда они делают ваш код понятнее, чем если бы вы их не использовали.

                                                            0
                                                            Да, вы правы! Совсем упустил этот момент. Не часто приходится сталкиваться с реализацией сложных алгоритмов.

                                                            Но на счет лапши из вызова методов — это спорный вопрос, чаще это дает возможность легче читать код. Хотя в случае тех же сложных алгоритмов, вызов методов будет просаживать производительность.
                                                      +2
                                                      >> Если lightbend не разорится, на 5-10 лет активного развития языка рассчитывать можно.

                                                      а чтобы не разориться он начал вкладываться и в java, а не только надеяться на scala

                                                      >> К тому же, Java развивается ОЧЕНЬ медленно — оракл не может себе позволить добавить в язык что-то трендовое и не проверенное временем.

                                                      зато скала развивается динамически и не имеет обратной совместимости, что заставляет людей не просто переписывать код, но иногда и думать как собрать сторонние либы под нужную версию.

                                                      Простой пример: есть ваш продукт X на scala 2.11 который использует библиотеку Y обязательно версии 2.11, попытка перейти на версию 2.12 вызовет необходимость патчить сразу свой код, а потом продолжать делать это и для библиотеки Y. Особенно интересной ситуация выглядит когда вы стартуете новый проект и пытаетесь использовать свежую скалу 2.10, но видите что одна из ваших зависимостей собрана только под 2.10, а другая заброшена на уровне 2.9, после этого часть пытаетесь сами перевести, часть накидать костылей.

                                                      Параллели java/scala и c/c++ некорректны хотя бы в совместимости, посмотрите сколько говна за собой тянет c++ ради обратной совместимости (да, не всегда получается, но зачастую об этом хоть думают). Не может язык который плевать хотел на свой же код и собранные библиотеки всего двухлетней давности стать промышленным стандартом, дальше стартапов где «написал-потыкал-выкинул-переписал» его не пустят.

                                                      Скала самому нравится, но с таким академическим подходом «сегодня добавим посмотрим очередную фичу, завтра поменяем, послезавтра вообще выпилим» у меня она остается на всяких генераторах тестовых данных или PoC.
                                                      +1
                                                      Лично я, в последнее время, слышу о скала как раз достаточно много, и вижу, что язык развивается и достаточно быстро. Недавно вышла Scala 2.12, есть Scala Native, ScalaJS и прочие. Ошибочно относиться к скале, как к Java++. Это совершенно другой язык, со своей философией и подходом к разработке. Конечно, можно писать код так, как писали бы его на джава, но это, в итоге, будет причинять только боль. И потом будут появляться статьи из серии, почему я бросил скалу и вернулся на джаву.

                                                      Так что, сколько бы плюшек в джаву не добавили — это не имеет значения, так как языки по своей природе разные.
                                                        0
                                                        Каждый язык живет, пока люди им пользуются. Мало того, что Java становится приятнее, так еще появляются другие конкуренты, тот же Kotlin.

                                                        Churn никуда не деть, и если люди уходят активнее, чем приходят — это стагнация
                                                          +1
                                                          А кто сказал, что со скалы люди уходят? Мне, кажется, наоборот, за последний год появилось достаточно много новых вакансий. По крайней мере на LinkedIn отбоя от рекрутеров нет и, периодически, попадаются предложения от серьезных кампаний. В сфере бигдаты скала уже практически стандарт, благодаря Spark и Flink.

                                                          Я вот не считаю, что Kotlin прямой конкурент Scala. Как раз он более походит на Java++ и у него значительно больше шансов пойти дорогой Coffeescript.
                                                            +2
                                                            spark — усиленно подтягивает java интерфейсы, в 2.0 все что есть по api в scala есть и в java

                                                            flink — для себя использует в первую очередь java, scala там как таковое в 2х местах table-api (но все обвязки и на java имеются) и в flink-ml (большинство алгоритмов внутри на scala сделаны)

                                                            apache beam — чистая java (а с ним вы получаете полную связку google dataflow/spark/flink/apex/gearpump), хотя spotify и прикрутил уже сбоку обвязку в виде scio

                                                            >> По крайней мере на LinkedIn отбоя от рекрутеров нет и, периодически, попадаются предложения от серьезных кампаний.

                                                            Систематическая ошибка внимания и Феномен Баадера-Майнхоф

                                                            =) сам склонен к этим симптомам

                                                            я больше склонен к позиции: больше людей начинают учить скалу
                                                            но нужно учесть, что наличие и знание других языков не означает повседневное его использование, так как многие вещи учишь только ради расширения своих знаний
                                                        +3
                                                        Все эти Java vs Scala, Coffeescript vs Javascript итд к сожалению обычно заканчиваются печально для тех, кто выбирает молодые языки.

                                                        Может, конечно, смотрю со своей колокольни, но не особо понимаю. Ну то есть, если пишешь на скале, то ведь и с джавой худо-бедно ознакомишься. Опять же, о ком мы говорим? Если это "молодой специалист", который толком опыта не имеет и ему удалось работу на скале найти, то сомневаюсь, что он пропадёт. А если это человек с опытом решил переквалифицироваться, то тем более.


                                                        Или предполагается, что человек без опыта хочет стать программистом и усиленно занимается изучением "молодого языка"? В этом случае, и правда стоит посмотреть на окружающие условия, но как по мне, это несколько особый случай.

                                                          +1
                                                          Сейчас действительно удобен Kotlin.
                                                            +1
                                                            > Рано или поздно под давлением комьюнити все нужные фичи появляются в базовых языках и через какое-то время конкуренты начинают умирать.


                                                            В Java фитчи из FP языков, например таких как Scala, не могут появится by design. Это даже теоретически невозможно без тотального слома обратной совместимости. Это как сделать из запорожца реактивный самолёт последнего поколения.

                                                            > О Скала последнее время слышно все меньше и меньше,
                                                            Да что вы говорите!? Читаю эти строки вернувшись пару часов назад с конференции Scala By The Bay, которая сейчас проходит в San Francisco :-) :-) Огромное кол-во компаний: от гигантов индустрии до стартапов…
                                                              0
                                                              image

                                                              MAU Scala на гитхаб сократился за 3 года в полтора раза, так что, похоже, я был прав
                                                                0

                                                                График интересный. Но появилось несколько вопросов. Первый — что такое MAU? Второй — а можно ссылку на оригинал?

                                                                    0

                                                                    Спасибо!


                                                                    Для тех, кому лень искать, вот подпись автора под этим графиком:


                                                                    Given the relatively small numbers here, there is more noise in the rankings. I'm also not convinced that the apparent decline of things like Clojure and Haskell is anything more than a result of GitHub growing more mainstream over time.

                                                                    Сенсации не вышло, расходимся...

                                                              0

                                                              Выбирать немейнстрим для чего-то крупного или потенциально крупного — это всегда большой риск. Через годы тренды сменятся, а кодовая база останется, и поддерживать её может оказаться некому. Всякое случается. Тут мне сразу вспомнилась вот эта статья, потому что как-то раньше не приходилось читать про элемент языка, который вообще непонятно что делает. Это забавно, но только в том случае, если не тебе приходится разгребать ситуацию. С выводом в статье о переходе на Go я лично, впрочем, не согласен, но это уже чисто моё мнение. Сам сделал ставку на Java и C++, которые точно никуда не денутся в обозримом будущем, и языковая/библиотечная мощность которых меня на данный момент полностью устраивает.


                                                              Из JVM-языков часто упоминают Kotlin, но почему-то совсем ничего не слышно про Ceylon, который тоже очень-очень неплох. Делается RedHat'ом и имеет поддержку в Eclipse, что логично, тогда как у Kotlin приоритетна IDEA.

                                                                +2

                                                                Это не элемент языка. Это элемент дизайна языка, позволяющий создавать операторы из произвольного набора символов пунктуации и элемент библиотеки, которая этим злоупотребляет.

                                                                  0

                                                                  Безусловно, как и перегрузка операторов в C++. Это мощная концепция, которую можно употребить очень неправильно, в итоге запутав код и сделав его неподдерживаемым. Мне кажется, этим и отличаются языки мощные/крутые/красивые от языков промышленных (C++ под этот критерий не очень подходит, согласен, но всё же является промышленным) — в последних дизайн языка требует писать скучно, уныло и абсолютно однозначно. Не в чем запутаться, код не блещет изящными решениями и потому может поддерживаться годами без особых усилий. Конечно, это лишь моё видение.

                                                                +1
                                                                > Рано или поздно под давлением комьюнити все нужные фичи появляются в базовых языках и через какое-то время конкуренты начинают умирать.

                                                                Экспериментальный язык всегда будет на шаг впереди. Пока основной язык заимствует проверенные многолетней практикой наработки экспериментального, экспериментальный придумывает новые. Ну а если они в конце-концов дойдут до идеала и идентичности, то не всё ли равно, каким языком пользоваться? Замените ключевые слова на их синонимы — и вот вы знаете оба языка, и не потеряли ничего.
                                                                +5
                                                                > Наверное, все уже согласны, что иммутабельные структуры данных — это Хорошая Идея. Scala позволяет писать иммутабельный код, не расставляя `final`
                                                                >
                                                                > public void method(final String a, final int b) {
                                                                > final String c = a + b;
                                                                > }

                                                                Да ладно? причет тут иммутабильность к final?
                                                                final в данном контексте — это всего лишь val, не более того;
                                                                Вы же писали, что с java переходили, а такую глупость пишите.
                                                                  0
                                                                  Даже я обратил на это внимание, хотя хотя мое знакомство с Java очень поверхностное.
                                                                  +2
                                                                  Может мне кто-нибудь объяснить, за что люди так любят иммутабельность?
                                                                    +1
                                                                    Если по простому — это сейчас модно!
                                                                    Идет в поставке вместе с чистыми функциями, лямбдами и монадами =)

                                                                    преимущество: ты его не можешь изменить, значит можешь свободно расшарить между потоками и не бояться, что у тебя возникнут проблемы синхронизации или гонки. Единственный способ изменить объект — создать новый. А это удобно для отладки и т.д. (так говорят).

                                                                    недостаток: но теперь, чтобы изменить значение нужно создать копию объекта с 1 измененным полем;
                                                                    чтобы заполнить один более-менее большой объект с данными нужно будет создать десяток копий, которые будут лежать на стеке и не будут собираться gc, пока стек не развернется (или создать изменяемый объект-билдер, который позволит создавать большие неизменяемые объекты).
                                                                      –1
                                                                      Какой-то добровольный выстрел в ногу… А потом сами жалуются, что jvm много ОЗУ требует.
                                                                        0
                                                                        Иммутабильность — это не только в jvm.

                                                                        А вот нападки на jvm потому, что она расходует памяти на что-то «левое». На мониторинг, на выравнивание памяти, на jit статистику, на gc (в некоторых крайних случаях, лабораторки в универе, gc может требовать памяти больше, чем сама программа).

                                                                        Все это требует потребления большего количества памяти, но в результате дает возможность увеличить производительность всей системы (в долгосрочной перспективе).
                                                                        0
                                                                        но теперь, чтобы изменить значение нужно создать копию объекта с 1 измененным полем;
                                                                        чтобы заполнить один более-менее большой объект с данными нужно будет создать десяток копий

                                                                        Не могу сказать как это в Scala реализовано, но в большинстве функциональных языков копирования не происходит, а общая часть структуры просто переиспользуется для второго объекта.

                                                                          0
                                                                          Так это и есть копирование. Копируется не все дерево объектов, копируется ссылка на поддерево (или значение для примитивов).
                                                                            0

                                                                            Так в чём копирование то? Если остальные поля объекта остались как есть, там где были, а изменённое поле стало существовать в двух ипостасях — старое значение и текущее значение.
                                                                            Имхо, слово "копирование" подразумевает дубликацию одних и тех же значений, а этого как раз не происходит.

                                                                              –1
                                                                              Копирование это не дублирование.
                                                                              Есть объект A правим какое-то значение, получаем новый объект A' (копируем все поля из A в A', одно заменяем), это в разы дешевле, чем глубокое копирование, но все же тоже копирование.
                                                                                0
                                                                                а теперь мы вспоминаем слова «многопоточность», «shared state» и «инвариант» и пытаемся понять, что делать со всей этой хренью в случае нескольких потоков. Кроме того, вспоминая слово «locality» мы понимаем, что вся локальность в вашей схеме теряется, все становится менее cache-friendly, начинаются походы в память, перфоманс начинает проседать и т.д. и т.п.

                                                                                Реально рецепт один — надо мерять. Что дороже — блокировки на изменяемых объектах или схема на CAS-loop'ах — в общем случае совершенно непонятно.
                                                                            0
                                                                            Билдер обычно реализуют с помощью цепочки вызовов. При этом на стеке ни чего не накапливается.
                                                                              0
                                                                              Но ведь билдер — это уже изменяемая структура данных.
                                                                              И это единственный адекватный способ создать большой неизменяемый объект избежав лишнего копирования.
                                                                            +2
                                                                            Потому что концепция иммутабельности выглядит как волшебная палочка позволяющая забыть о проблемах многопоточности и «неконсистентности» данных, если не обращать внимания на то что все это реализуется на существующем сегодня железе, а значит является обеткой над мутабельной памятью.

                                                                            Еще, если заняться интенсивным аутотренингом, можно убедить себя что мы живем в stateless мире к которому иммутабельные данные очень подходят.

                                                                            В итоге это обычно выливается в reverse массива за O(n * log n) или грязные хаки, когда данные вообще иммутабельные, но если сильно нужно — мутабельные.

                                                                            В общем, выглядит замечательно пока думаешь о структурах с двумя полями, и жутко неудобно в реальном мире.
                                                                              +3

                                                                              Прежде всего за упрощение кода. Допустим у нас есть два одинаковых класса — один иммутабельный (все его поля заполняются через конструктор, для модификации нужно создать другой экземпляр класса), а второй — мутабельный, т.е. его состояние можно менять через сеттеры. Теперь смотрите разницу:


                                                                              • поля класса часто бывают зависимы, к примеру, в нашем классе должно быть заполнено или поле А, или поле B. В мутабельном классе невозможно гарантировать этот инвариант — для смены состояния потребуется два вызова сеттеров. Можно сделать отдельный метод, можно написать в сеттерах код, проверяющий инварианты, можно, как в спринге, сделать отдельный метод инициализации, который будет проверять инварианты. Но всё это значительно сложнее, чем конструктор с простой проверкой
                                                                              • Атомарность внесения изменений. Для иммутабельных структур данных изменения "применяются" только тогда, когда новый объект будет вставлен вместо старого. Помимо уже упоминавшейся многопоточности, это позволяет оставить программу в неразрушенном состоянии при возникновении исключения в процессе внесения изменений
                                                                              • Иммутабельный код проще понимать. Когда ты знаешь, что эти переменные final и не могут быть изменены, можно рассматривать меньше вариантов поведения программы при чтении и "вычитке" кода
                                                                              • Модульность и тестирование. Если состояние какого-то модуля иммутабельное, то для смены этого состояния нужно построить новое дерево объектов, что, как правило, делается одним методом или конструктором. Куда можно вписать логгирование, который можно вызывать из тестов для воспроизведения нужного состояния и т.п.
                                                                              • Хорошо работает с чистыми функциями(результат выполнения которых зависит только от входных параметров). Чистые функции легче писать, понимать, тестировать и поддерживать.
                                                                                0
                                                                                А теперь объясните мне пожалуйста, зачем в Java добавили сеттеры и геттеры. По-моему, это откат к процедурному программированию, а значит ухудшение кода (усиление связанности -> уменьшение надежности). Я тут просто Егора Бугаенко yegor256 наслушался, теперь сомневаюсь в стратегии, куда идет язык…
                                                                              0
                                                                              Она очень упрощает жизнь. И программисту, и компилятору, и системе сборки мусора.
                                                                              –2
                                                                              Наверное, все уже согласны, что иммутабельные структуры данных — это Хорошая Идея.

                                                                              Нет, не согласны. С чего это? Немутамебльные структуры являются хорошей идеей только тогда, когда подразумеваются сценарии многопоточного доступа к данным и вы действительно можете себе позволить забрасывать управляемую кучу новыми порожденными объектами на каждый чих. На практике, иммутабельные структуры — это попытка убежать от примитивов синхронизации и прочих штук, которые специально созданы для многопоточности, потому что они, видите ли, сложны в использовании.

                                                                              Иммутабельные структуры — не панацея, и в «бытовом» программировании они мало кому нужны.
                                                                              • UFO just landed and posted this here
                                                                                  +7

                                                                                  Иммутабельные структуры — это попытка убежать от изменения состояния объекта.


                                                                                  Если объект мутабельный, для использования его методов может быть необходимо сначала выставить подходящее состояние объекта. Проще простого забыть это сделать (даже в однопоточной среде). В многопоточной среде это может быть или невозможно (если нет синхронизации), или медленно (если синхронизация есть). Иммутабельность неплохо решает эти проблемы.
                                                                                  (Поэтому я считаю, что архитектура с иммутабельными объектами обычно лучше, даже если поток один).


                                                                                  Однако, когда нужна высокая производительность при изменении больших объёмов данных в памяти, от иммутабельности (и многих фич из ФП) лучше отказаться.

                                                                                    +1

                                                                                    Иммутабельные структуры — это хорошая идея просто потому, что они проще. Они ближе к математике. У них не могут испортиться инварианты, их можно спокойно шарить между разными объектами. Допустим, десять объектов ссылаются на одну и ту же строку, это экономит память и не усложняет код. Какие альтернативы? (Предположим, что "бытовой" string стал изменяемым)


                                                                                    1. Хранить ссылки на общий объект и надеяться, что его никто не изменит. Вариант плохой, в java нет слова const и нельзя запретить менять объект.
                                                                                    2. Хранить в каждом объекте копию изменяемого объекта — расходует память.
                                                                                    3. Сделать обёртку над классом, которая не даст изменить объект. Хм. Где-то мы это уже видели…
                                                                                      Причём неизменяемый объект лучше, чем обёртка над изменяемым. Иммутабельность утверждает, что объект не изменится в течении всего времени существования — это упрощает понимание программы.
                                                                                      +1
                                                                                      > Предположим, что «бытовой» string стал изменяемым

                                                                                      Мы получим Ruby, PHP, C/C++ и много других. Не самые плохие из языков, довольно даже популярные))

                                                                                      Но в целом согласен с тем, что неизменяемые структуры — это хорошо! Но не стоит их использовать повсеместно, фанатизм еще ни к чему хорошему не приводил.
                                                                                      0
                                                                                      в точку. Люто, бешено плюсую.
                                                                                      +1

                                                                                      Обычно scala критикуют за высокий порог входа, необходимый для использования этих (полезных) фич. Поэтому задам типичный вопрос: у вас сколько человек в команде?


                                                                                      Если больше одного, ещё пара вопросов:


                                                                                      1. Удобно ли вести командную разработку проекта на scala, когда приходится понимать и переписывать чужой код?
                                                                                      2. Хотели бы вы писать на scala следующий проект?
                                                                                        –2

                                                                                        Высокий порог входа в Scala — это, скажем так, заблуждение. Берет человек книжку programming in scala, дочитывает до описания системы типов и у него сворачиваются мозги. Отсюда и высокий порог. Изучать скалу с нуля тяжело просто потому, что в скале много языковых фич, полезных только разработчикам библиотек и апологетам ФП. В промышленном же программировании используется небольшое подмножество, не слишком усложняющее код.


                                                                                        Вот хороший пример очень большого, но понятного проекта, написанного на скале: https://github.com/twitter/finagle
                                                                                        И рекомендации по написанию качественного кода: http://twitter.github.io/effectivescala/


                                                                                        по вопросам:


                                                                                        • маленькие команды, но это не связано с языком.
                                                                                        • да, если все члены команды уже переболели "давайте напишем этот метод как можно короче". Скала дает много способов написания нечитаемого кода, так что это язык для сеньоров.
                                                                                        • да.
                                                                                          0

                                                                                          Сколько людей в команде вы имеете в виду под "маленькие команды"? Можете указать числовой диапазон?

                                                                                            0

                                                                                            2-4

                                                                                            +3
                                                                                            > Скала… это язык для сеньоров

                                                                                            Ага-ага, а java — для жалких джунов, которые даже с монадами не могут разобраться :-)
                                                                                              +1

                                                                                              Java — это язык для всех.
                                                                                              И у меня для вас новость — java.util.Optional является монадой. Так что не так страшны монады, как их малюют :-)

                                                                                                0
                                                                                                Всё декларативное программирование больше для сеньоров…
                                                                                                • UFO just landed and posted this here
                                                                                                    +3
                                                                                                    • UFO just landed and posted this here
                                                                                                        0
                                                                                                        монаде, по идее, должны быть применимы те же операции, что и к исходному типу
                                                                                                        монадой был бы код, трансформирующий некий набор функций

                                                                                                        Сдаётся мне, вы не понимаете, что такое монада. Монада — это параметризованный тип M[T], снабжённый операциями (pure(T): M[T], map(T => V): M[T] => M[V], join(M[M[T]]): M[T]), которые удовлетворяют законам.
                                                                                                        Ничто не мешает использовать монады в java.

                                                                                                        • UFO just landed and posted this here
                                                                                                            +1
                                                                                                            Чтобы утверждать, будто «нечто» _НЕ_ является монадой, неплохо бы для начала определиться с тем, что такое монада. К сожалению, очень мало программистов понимают, что это такое на самом деле. Почему так произошло, и откуда пошли слухи, что «монада» — лютый зверь, мне неизвестно. Это всё происходило, когда меня ещё не было.

                                                                                                            Самым точным определением монады является формальное математическое определение из теории категорий: Монада — моноид в категории эндофукторов. А только потом данную концепцию перенесли в языки программирования, потому что она оказалась полезной. К сожалению, с пониманием этого определения среди программистов возникает другая проблема: очень мало людей среди них разбираются в теории категорий. И многие слышали про монады через какие-то слухи, мнения других, свой опыт, подобные комментарии на хабре, etc. И в итоге выходит, что люди спорят ниочём: либо тролли, либо показывают своё невежество, либо кормильцы троллей, либо пытающиеся образумить невежд.

                                                                                                            В итоге получается, что многие программисты пытаются объяснить монады через какие-то примеры, куски кода, конкретные подходы, частные случаи. Всё это выглядит в большинстве случаев как попытка натянуть слона за яйца на глобус (или как-то так, не помню точного оборота). С этой проблемой сталкиваюсь и я, когда пытаюсь объяснить монады студентам на лекциях в универе, ибо они теорию категорий тоже не проходили, к сожалению. Но, к счастью, объяснить монады всё же возможно через какие-то достаточно понятные, прикладные и знакомые концепции. А каждый частный пример не даёт достаточно полного понимания, либо содержит какие-то неувязочки. Вроде того, что «Optional в Java — монада». И у разных людей такие высказывания вызывают реакцию «Вроде бы да, но...» с разной степенью агрессивности :)
                                                                                                              0

                                                                                                              Можно тогда ваше мнение о том, что такое монада? Монада в джаве, допустим, это:


                                                                                                              public class Monad<T> {
                                                                                                                  private T value;
                                                                                                                  //методы, которые делают этот класс монадой
                                                                                                              }

                                                                                                              Пожалуйста, дополните этот код, чтобы класс Monad можно было назвать монадой.

                                                                                                                +1
                                                                                                                Во-первых, по некоторым политическим и религиозным соображением в Java не определить монаду в полном смысле. Можно лишь некоторое приближение. Потому что как минимум система типов в Java недостаточно мощная, чтобы дать все гарантии на этапе компиляции, которые выполняются для монады. Поэтому реализация будет достаточно точной проекцией с учётом несовершенства системы типов в Java.

                                                                                                                Во-вторых, класс монад в Java должен быть interface, а не class. Сама по себе «монада» не говорит, что в ней хранится. Она лишь говорит, что с ней можно делать. А уже конкретная реализация описывает, с какими данными предстоит работать. Следовательно, интерфейс монады с достаточно близким приближением можно описать подобным образом в Java:

                                                                                                                public interface Monad<T> {
                                                                                                                    <R> Monad<R> bind(Function<T, Monad<R>> f);
                                                                                                                }
                                                                                                                


                                                                                                                Вообще говоря, монада определяет ещё метод pure следующего вида:

                                                                                                                public <T> Monad<T> pure(T x);
                                                                                                                


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

                                                                                                                Минимальная реализация чего-то похоже на Optional выглядела бы следующим образом:

                                                                                                                public class MyOptional<T> implements Monad<T> {
                                                                                                                    private T value;
                                                                                                                
                                                                                                                    public MyOptional() {}
                                                                                                                    public MyOptional(T value) {
                                                                                                                        this.value = Objects.requireNonNull(value);
                                                                                                                    }
                                                                                                                
                                                                                                                    public <R> Monad<R> bind(Function<T, Monad<R>> f) {
                                                                                                                        if (value == null) {
                                                                                                                            return new MyOptional<>(null);
                                                                                                                        } else {
                                                                                                                            return f.apply(value);
                                                                                                                        }
                                                                                                                    }
                                                                                                                }
                                                                                                                
                                                                                                                  0
                                                                                                                  Немного поторопился :(
                                                                                                                  Вместо

                                                                                                                  return new MyOptional<>(null);
                                                                                                                  


                                                                                                                  надо писать

                                                                                                                  return new MyOptional<>();
                                                                                                                  


                                                                                                                  Была бы очень неприятная ошибка. Ну, могу сказать, что какой-нибудь хороший язык вроде Haskell не дал бы её совершить уже на этапе компиляции :)
                                                                                                                +2

                                                                                                                Помню, ко мне пришло осознание через аналогию с теорией групп. Людям непросто объяснить, что такое группа, потому что это понятие абстрактное. А на деле найди множество и операцию, проверь законы. Выполняются? Группа. Получи пачку теорем и алгоритмов бесплатно.
                                                                                                                Ну и с монадами та же примерно история. Найди правильные функции, проверь законы. Сложнее всего начать видеть такие абстрактные концепции в конкретных вещах.

                                                                                                                  0

                                                                                                                  Дело просто в том, что вы описываете выше монады с точки зрения математика.


                                                                                                                  Для прикладного программиста (не изучавшего теорию категорий) в знании того, что "монада это моноид и т.д." обычно очень мало толку. Для него польза от монад состоит в том, что они дают удобные средства композиции программы из функций. И вот в этом-то смысле Optional в Java все-таки монада (хотя и «да, но» имеют место — потому что законы мы допустим проверить не можем). Почему такие объяснение имеют место? Да потому что имено в этом, в принципах построения программы при помощи монад, и состоит та польза, которую почти каждый может от них получить.

                                                                                                                0

                                                                                                                А мне сдаётся, что Вы путаете аппликативные функторы и монады :-)

                                                                                                                  0
                                                                                                                  Вы путаете аппликативные функторы и монады :-)

                                                                                                                  Не путаю. Каждая монада по определению является функтором. И аппликативным функтором (pure == return). Покажите мне join :: m (m a) -> m a у аппликативного функтора.

                                                                                                                    0
                                                                                                                    Каждая монада по определению является функтором. И аппликативным функтором

                                                                                                                    Функтором — да, аппликативным функтором — как правило, да, но не по определению.
                                                                                                                    Да и какой смысл принуждать реализовывать bind через join fmap? Где Вы такое определение монад вычитали?

                                                                                                                      +1
                                                                                                                      Да и какой смысл принуждать реализовывать bind через join fmap?

                                                                                                                      Кого принуждать? Я вроде никого не принуждаю, просто привожу одно из возможных определений. С моей точки зрения, join и fmap гораздо проще для понимая, чем bind, который, кстати, в Scala зовётся flatMap, что буквально означает композицию join и fmap.
                                                                                                                      Более того, в теории категорий монада обычно определяется через join и map, это адекватно отражает моноидальную структуру.


                                                                                                                      Где Вы такое определение монад вычитали?

                                                                                                                      Да где угодно, хоть википедию откройте:
                                                                                                                      https://en.wikipedia.org/wiki/Monad_(functional_programming)#fmap_and_join
                                                                                                                      https://en.wikipedia.org/wiki/Monad_(category_theory)


                                                                                                                      Ну и вот тоже занятное чтиво
                                                                                                                      http://anton-k.github.io/ru-haskell-book/book/15.html#монады

                                                                                                    0
                                                                                                    Расскажу про себя. Над Scala-проектами (микросервисами) работают 6 разработчиков и 2 тестера (использующих питон). Двое разработчиков еще участвуют в проектах на C#.

                                                                                                    1. Удобно. Недавно к нам пришли 2 джависта и освоили Scala до уровня «исправить баг» очень быстро. Самая большая проблема была с фьючами — в автотестах, которые пишут сами разработчики мы слишком ими увлеклись и начинающим было трудно в них разобраться.

                                                                                                    2 Да. Мы даже постепенно переписываем старые Java-сервисы.
                                                                                                    +1
                                                                                                    Java или Scala в целом без разницы. Язык возможно критичен для кодера, но не нормального Программиста с большой буквы, у которого время затрачиваемое на разработку по большей части расходуется на грамотное продумывание дизайна классов, интерфейсов, алгоритмов, а написать сам код как правило не составляет труда на любом языке в сходной весовой категории, ну напишет он метод на Java на 2 минуты дольше — ничего страшного, да хоть на 30 минут дольше, главное чтобы руки росли из нужного места и это всё потом работало качественно и долго.
                                                                                                      +1
                                                                                                      Если язык не важен, то почему вы ООП программируете на джаве, а не на фортране?
                                                                                                        +3
                                                                                                        > время затрачиваемое на разработку по большей части расходуется на грамотное продумывание дизайна классов, интерфейсов, алгоритмов

                                                                                                        Это без сомнения так, но дизайн классов и интерфейсов, а так же выбранные алгоритмы уже непосредственно будет зависеть от языка и его философии.

                                                                                                      Only users with full accounts can post comments. Log in, please.