Scala как первый язык

Эта статья, как и мой предыдущий пост, не похожа на то, что обычно публикуют на Хабре.  Здесь не объясняется никаких новых или старых концепций, я не рассказываю что такое ООП и функциональное программирование, сложного кода почти нет. Я хочу пригласить вас к дискуссии стоит ли начинать программировать с языка Scala.

Меня иногда просят научить программированию или помочь с поиском подходящего курса. Я хорошо понимаю недостатки и сложности со скалой, но думаю, что Scala 3 — подходящий язык, для того чтобы начать обучение с него, если правильно составить курс. Вся языковая мощь и сложность, конечно, не нужны начинающему программисту, но ему и незачем о них знать. На скале можно писать вполне простой и понятный код, постепенно наращивая инструментарий.

Я согласен с теми комментаторами, кто считает что для этого нужен толковый преподаватель. Это безусловно. Или талантливый преподаватель, который разбирается в предмете, или хорошая книжка, или толковый курс просто необходимы. Иначе есть риск захлебнуться, так и не научившись плавать.

И тем не менее я считаю, что Scala — это язык будущего.

Лестница в логотипе отсылает к институту EPFL в Лозанне. Там придумали этот язык
Лестница в логотипе отсылает к институту EPFL в Лозанне. Там придумали этот язык

Если коротко, то Scala — это возможность научиться функциональному программированию на безопасном языке, у которого есть большое будущее

Умный компилятор

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

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

JVM-экосистема

Как известно, Джеймс Гослинг, создатель языка джава, считает самой лучшей ее частью джава-машину. Действительно, много инженеров потратило десятки человеко-лет на разработку виртуальной машины и достигли скоростей, в некоторых случаях превышающих Си++. Вот исследование производительности JVM в мобильных устройствах, в нем чаще побеждает нативный код на Си, но в одном случае победила JVM: Java vs C app performance.

На Android 6 AArch64 JVM победила Си в математических вычислениях, хотя и проиграла во всех других видах
На Android 6 AArch64 JVM победила Си в математических вычислениях, хотя и проиграла во всех других видах

Java Memory Model (Модель памяти для многопоточных вычислений) — это зрелая, непротиворечивая, проверенная многими годами промышленного программирования парадигма, которая при правильном использовании гарантирует достаточный уровень абстракции и безопасности. Благодаря этому возможны удобные конструкции для параллельного программирования, доступные даже начинающим.

Кроме того, на джаве написаны миллионы строк кода, которые вы можете использовать из скалы или без проблем в нее транслировать.

Кстати, Джеймсу Гослингу скала тоже нравится.

Но в этом всем есть и минусы. Как мы знаем, верхнеуровневые абстракции протекают, и для того чтобы программировать на скале, важно знать как устроена виртуальная машина джава, и учитывать ее особенности. Например, такие как Type Erasure. Это довольно серьезный минус, но плюсы от использования JVM его перевешивают.

Эволюция vs революция

В экосистеме скалы приняты довольно слабые гарантии обратной совместимости по сравнению с джавой. С одной стороны, это приводит к тому, что разработчикам постоянно приходится поддерживать свой код в форме при переходе на новую версию языка или библиотек. Кроме того, разработчикам библиотек приходится прибегать к кросс-компиляции для того чтобы обеспечить несколько версий скомпилированных библиотек, подходящих для нескольких версий языка. Это, безусловно, минус.

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

К тому же, в Scala 3 появилось типизированное абстрактное синтаксическое дерево компилятора TASTY, которое позволит взаимодействовать классам, собранным разными версиями компилятора. Разумеется, начинающим программистам нет нужды разбираться в этом.

Scala 3

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

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

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

Я уже пару лет с нетерпением жду его выхода и мечтаю начать писать на нём. Вот сжатый рассказ Мартина Одерски про новую версию языка: Countdown to Scala 3 by Martin Odersky. Для опытных разработчиков — интересная статья Annoying things in Scala 2 that’ll be (mostly) gone in Scala 3

DOT

Dependent Object Types — это теоретические основы языка Scala 3, разработанные его основателем Мартином Одерски. Мало какой язык может похвастать математически точным исчислением, лежащем в его основе.

Мартин Одерски
Мартин Одерски

Согласитесь, приятно учить язык с таким бэкграундом, хотя начинающим программистам знать о нём не обязательно.

Выразительность и лаконичность

То, что я больше всего люблю в языке — это его сжатость и лаконичность. Я ненавижу длиннейшие конструкции джавы, в которых приходится сложно и многословно объяснять компилятору простые вещи. Моя любимая шутка про джаву — что это такой язык, в котором уан-лайнер занимает около 30 строк. Так вот, в скале уан-лайнер — это уан-лайнер.

Я думаю, что это качество важно не только для опытных разработчиков, но и для тех кто только изучает язык. Думаю, выразительность — это та причина, по которой так популярны динамические и скриптовые языки. Уверен, скала способна с ними в этом поспорить. И даже сама послужить отличным скриптовым языком.

Конечно, лаконичность не должна наносить ущерб читаемости кода. Таких неудачных примеров в программировании полно, вспомним регулярные выражения, паттерн-матчинг и парсер-комбинаторы. Понятно, что для написания библиотек важно понимать сложные концепции и знать много умных слов. Но для того, чтобы ими пользоваться и писать простой код, всего этого знать не надо. Минимальный уровень скалы, который подойдет начинающим, очень простой.

Вот мой любимый пример для библиотечного кода на скале. Конечно, он не предназначен для начинающих разработчиков:

class Stack[+A] {

  def push[B >: A](elem: B): Stack[B] = new Stack[B] {
    override def top: B = elem
    override def pop: Stack[B] = Stack.this
    override def toString = s"$elem ${Stack.this}"
  }

  def top: A = sys.error("no element on stack")
  def pop: Stack[A] = sys.error("no element on stack")
  override def toString = ""
}

object VariancesTest extends App {
  println(Stack().push("hello").push(Object()).push(7))
}

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

enum IndentWidth:
  case Run(ch: Char, n: Int)
  case Conc(l: IndentWidth, r: Run)

  def <= (that: IndentWidth): Boolean = this match
    case Run(ch1, n1) =>
      that match
        case Run(ch2, n2) => n1 <= n2 && (ch1 == ch2 || n1 == 0)
        case Conc(l, r)   => this <= l
    case Conc(l1, r1) =>
      that match
        case Conc(l2, r2) => l1 == l2 && r1 <= r2
        case _            => false

  def < (that: IndentWidth): Boolean =
    this <= that && !(that <= this)

  override def toString: String = this match
    case Run(ch, n) =>
      val kind = ch match
        case ' '  => "space"
        case '\t' => "tab"
        case _    => s"'$ch'-character"
      val suffix = if n == 1 then "" else "s"
      s"$n $kind$suffix"
    case Conc(l, r) =>
      s"$l, $r"

object IndentWidth:
  private inline val MaxCached = 40

  private val spaces = IArray.tabulate(MaxCached + 1)(new Run(' ', _))
  private val tabs = IArray.tabulate(MaxCached + 1)(new Run('\t', _))

  def Run(ch: Char, n: Int): Run =
    if n <= MaxCached && ch == ' ' then
      spaces(n)
    else if n <= MaxCached && ch == '\t' then
      tabs(n)
    else
      new Run(ch, n)
  end Run

  val Zero = Run(' ', 0)
end IndentWidth

Статическая типизация

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

Именно по этой причине на мой взгляд не стоит начинать обучение с Питона, Руби, Джаваскрипта, Си и Си++. Динамическая типизация — это верный способ выстрелить себе в ногу.

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

ООП

Объектно-ориентированное программирование — это самая популярная парадигма, без которой не обходится не один современный язык программирования.

В скале эта парадигма изначально присуща языку, в отличии от Питона, Си/Си++ и в каком-то смысле джаваскрипта. Разумеется, сейчас у этих языков с ООП полный порядок.

Функциональное программирование

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

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

Иммутабельность

Вообще-то это свойство функционального программирования. Мне кажется очень важным прививать умение пользоваться неизменяемыми структурами данных с самого начала. Это позволит в будущем создавать безопасный многопоточный код. И не только многопоточный.

Расширяемость

Как известно, название языка изначально преподносилось как аббревиатура Scalable Language. Особенности языка позволяют писать гибкие и красивые DSL, удобные даже для не-программистов, вкладывать абстракции друг в друга, создавать очень удобные библиотеки и простые скрипты.

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

Мощь

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

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

Источник: https://prwatech.in/blog/apache-spark/introduction-to-scala-programming-language/
Источник: https://prwatech.in/blog/apache-spark/introduction-to-scala-programming-language/

Рынок вакансий

Конечно, вакансий для скала-программистов значительно меньше, чем для джава-программистов. Но зато Scala выше оплачивается.

https://insights.stackoverflow.com/survey/2019
https://insights.stackoverflow.com/survey/2019

Вот вам картинка про области применения скалы:

Источник: https://prwatech.in/blog/apache-spark/introduction-to-scala-programming-language/
Источник: https://prwatech.in/blog/apache-spark/introduction-to-scala-programming-language/

Мои первые книжки

Самая лучшая книжка про скалу, которую я читал — Scala by Example Мартина Одерски, написанная уже 10 лет назад. Прежде чем начинать сейчас читать книгу по скале, очень рекомендую убедиться что она обновлена до версии  Scala 3.

А любимый курс — это Functional Programming in Scala, я проходил его в самой первой версии, с тех пор он, конечно, успел измениться. Первые уроки этого курса основываются все на той же Scala by Example. Сейчас команда курса работает над его обновлением.

Если вы хотите поиграть скалой или дотти, не устанавливая IDE — добро пожаловать в Scastie.

Пример кода

Много примеров короткого кода на скале можно найти вот в этом обсуждении: Samples of Scala and Java code where Scala code looks simpler/has fewer lines? Вот один из них:

Scala

object Main extends App {
  val keywords = List("Apple", "Ananas", "Mango", "Banana", "Beer")
  val result = keywords.sorted.groupBy(_.head)
  println(result)
}

Java 8

import java.util.*;

class Main {
  public static void main(String[] args) {
    List<String> keywords = Arrays.asList("Apple", "Ananas", "Mango", "Banana", "Beer"); 
    Map<Character, List<String>> result = keywords.stream().sorted().collect(Collectors.groupingBy(it -> it.charAt(0)));
    System.out.println(result);
  }
}

Java 7

import java.util.*;

class Main {
  public static void main(String[] args) {
    List<String> keywords = Arrays.asList("Apple", "Ananas", "Mango", "Banana", "Beer"); 
    Map<Character, List<String>> result = new HashMap<Character, List<String>>(); 
    for(String k : keywords) {   
      char firstChar = k.charAt(0);     
      if(!result.containsKey(firstChar)) {     
        result.put(firstChar, new  ArrayList<String>());   
      }     
      result.get(firstChar).add(k); 
    } 
    for(List<String> list : result.values()) {   
      Collections.sort(list); 
    }
    System.out.println(result); 
  }
}

Поступь прогресса

На прощанье — шутка Кея Хорстмана «The March of Progress»

1980: C 

printf("%10.2f", x);

1988: C++

cout << setw(10) << setprecision(2) << fixed << x;

1996: Java

java.text.NumberFormat formatter = java.text.NumberFormat.getNumberInstance(); 
formatter.setMinimumFractionDigits(2); 
formatter.setMaximumFractionDigits(2); 
String s = formatter.format(x); 
for (int i = s.length(); i < 10; i++) System.out.print(' '); 
System.out.print(s);

2004: Java

System.out.printf("%10.2f", x);

2008: Scala and Groovy

printf("%10.2f", x)

2012: Scala 2.10

println(f"$x%10.2f")

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

Комментарии 82

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


    А можно ссылку на замеры? Или это просто так сказано, чтобы похвалить JVM?
      +2
      Спасибо. Добавил ссылку на замеры для андроида. Чаще JVM конечно проигрывает нативному коду, но есть случаи когда побеждает. Поищу еще ссыллок

      www.androidauthority.com/java-vs-c-app-performance-689081
      +6
      На мой взгляд: не стоит начинать программировать с языка Scala.

      Причины:

      У скалы один из самых сложных компиляторов

      важно знать как устроена виртуальная машина джава, и учитывать ее особенности. Например, такие как Type Erasure

      появилось типизированное абстрактное синтаксическое дерево компилятора

      Объектно-ориентированное программирование

      Функциональное программирование

      умение пользоваться иммутабельными структурами данных

      безопасный многопоточный код

      гибкие и красивые DSL, вкладывать абстракции друг в друга


      ну и самое главное

      вакансий для скала-программистов значительно меньше, чем для джава-программистов
        +1
        Зато много вакансий спарк программистов. И хорошие зарплаты.
          +1
          Не, на самом деле тут есть рациональное зерно. Я бы так сказал — скала в качестве первого языка требует наличия хорошего преподавателя. Чтобы правильно спланировать обучение и ограничить набор тех вещей, которые обучающемуся нужно запомнить одновременно.
            0
            ну то есть мало реализуемо на практике
              0
              В смысле таких преподавателей мало? Ну да, пожалуй что так.
          +1

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

            –2
            Scala слишком сложен для новичков. Лучше для начала хорошо освоить ООП стиль на примере Java или Python. А затем уже смешивать его с функциональным.
              +5

              Питон — это не про ооп и не про стиль. Из-за гибкости и вседозволенности питона в нём на ура используются подходы, которые в других языках считаются антипаттернами.
              1) наследование в питоне есть, но его почти не используют. Из-за динамической типизации очень легко сломать код при наследовании, сложных иерархий не делают.
              2) типизация утиная, интерфейсы и абстрактные методы практически бесполезны. Их тоже почти не используют. Теоретически, можно обложиться модулями типа abc, но это не похоже на pythonic way.
              3) инкапсуляции нет, давать название с двойным подчёркиванием — просто общепринятая практика, но эти поля всё равно доступны для изменения.
              А вот Java реально хороша для изучения — язык прям создан под ООП и он довольно строгий, чтобы заставлять пользователя красивый с точки зрения ООП код.

                –1

                В чем именно проблема с наследованием в Питоне?
                Из-за динамической типизации? Если так, то это легко лечится

                  0
                  3) инкапсуляции нет, давать название с двойным подчёркиванием — просто общепринятая практика, но эти поля всё равно доступны для изменения.

                  Ну тогда и в джаве её нет, через рефлексию можно достучаться до приватных членов. Зато в JS внутрь замыкания, насколько я знаю, нельзя залезть из самой программы. Вот там инкапсуляция так инкапсуляция!


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


                  На самом деле, инкапсуляция и видимость членов класса — это немного разные вещи, хотя многие java/c/c# программисты считают их синонимами. Настоящий смысл инкапсуляции — в сокрытии деталей реализации, а не в невозможности их каким-то образом посмотреть.

                    –1
                    Странно, что Вас минусуют.
                      +1
                      Ну тогда и в джаве её нет, через рефлексию можно достучаться до приватных членов

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


                      Нет, совсем не странно, такие вещи писать должно быть вообще стыдно.
                        0
                        Никакие вещи не должно быть стыдно писать.
                        Человек пишет то, что считает правильным.
                        Может, он знает/понимает меньше чем Вы, а может — больше (из короткого диалога это скорее всего будет непонятно).
                          0
                          Никакие вещи не должно быть стыдно писать.
                          рукалицо
                            0
                            Если, допустим, кто-то понимает какую-то тему на порядок глубже, чем Вы, ему, по-Вашему, должно быть стыдно писать своё мнение только потому, что есть риск, что Вы не поймётё до конца его позицию и сочтёте его дураком?
                            (А может и нет, может, наоборот, он хуже Вас знает. Но это в любом случае должно выясняться аргументами (ну или не выясняться вообще — разошлись при своих мнениях из-за нехватки времени), а не «ай-ай-ай»/«фу-фу-фу» и подобными эмоциональными манипуляциями.)
                              0
                              Просто когда говорят, что «иногда инкапсуляция мешает работать», то возникает вопрос — может человек вообще хочет вернуть GOTO? А на замечание, что это не комильфо, он отвечает «а мне комильфо». Ну, и применив бритву Окама, получаем вывод, что данный персонаж плохо разбирается в теме.
                                0
                                Вы перекручиваете. Человек писал слово инкапсуляция в кавычках, подразумевая, что иногда области видимости мешают работать (и что они не есть настоящая инкапсуляция).
                                  0

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


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


                                  Недавно надо было изменить алгоритм проверки жизни jwt-токена в одной библиотеки для oidc. Пришлось делать форк библиотеки просто потому что авторы не предусмотрели, что эту проверку нужно будет заменить, а вместо этого решили запрятать её глубоко в недра. Было бы там побольше экспортируемых классов — всё обошлось бы малой кровью и небольшим количеством кода. Самое смешное, что в другой библиотеки для работы с oidc такие же проблемы — метод с проверкой токена приватный, так что нужно переписывать почти весь класс, вместо того чтобы поменять 1 строчку.


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

                        0
                        >Ну тогда и в джаве её нет
                        Ну, это все же не совсем одинаковые случаи.
                      +6
                      Лучше для начала хорошо освоить ООП стиль на примере Java или Python

                      Если честно, я бы советовал начинать с функционального стиля, а не ООП. Оно сильно проще и полезнее приучить мозги к ФП, а потом уже пробовать ООП. Для меня ООП в стиле джавы — сплошные костыли после изучения ФП.

                        0
                        Да, такой вариант тоже может иметь смысл. Главное не смешивать эти 2 стиля до того момента, когда придет понимание их достоинств и ограничений.
                          0
                          Почему не смешивать-то?
                            +1
                            Потому что весьма вероятно будет каша. В моей практике обучения скале как раз это обычно вызывало больше всего вопросов. Почему вот тут функция, а вот тут какой-то метод какого-то объекта? Как это логично объяснить, ну кроме того, что автор такой API придумал? А если нельзя логично объяснить — то сложно запомнить.
                              +1
                              Ну, не знаю… С моей точки зрения ФП и ООП полноценны только в паре (использовать ООП без ФП или ФП без ООП это как пытаться ходить только левой ногой или только правой — можно, но зачем?). (Точнее говоря, с моей точки зрения, ООП и ФП идут к одному и тому же с разных сторон, т.е. «настоящее ООП»=«настоящее ФП», только не все языки и среды проходят этот путь до конца.)
                                0

                                Ну хз, пишу на языке с чистым ФП и не знаю проблем, потребности в ООП около нуля.

                                  0

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

                                    0
                                    Ну, вот я как раз их обоих воспринимаю как синтаксический сахар над классическим процедурным программированием.
                                    Не вижу причин ударяться в какую-то «метафизику» на пустом месте.
                                      0
                                      Всё есть синтаксический сахар над последовательностью нулей и единиц, но вы же все-таки предпочитаете писать на высокоуровневых языках программирования?
                                        0
                                        ИМХО: высокоуровневые языки хороши тем, что (как правило) расширяют возможности, а если они их (безосновательно) сужают, то лучше нафиг.
                                          0

                                          Сужение возможности стрелять по ногам – это, как правило, очень даже основательно.

                                0
                                Одну и ту же задачу можно реализовать как в ООП так и в функциональном стиле. Грубо говоря, ООП лучше подходит, если приложение ориентированно на данные, функциональный стиль — если на вычисления. Чтобы выбрать правильный стиль для каждой части приложения нужен опыт. Новичку очень трудо будет объяснить эти ньюансы. Ему для начала надо освоить оба этих стиля по отдельности и на практике прочувствовать их ограничения. Только после этого он сможет понять, как их можно смешивать.
                                  –1
                                  Ну, свою точку зрения я уже описал в другом месте: #comment_22220626. ИМХО, не бывает ОО-стиля и функционального стиля, ООП и ФП стремятся к одному и тому же, просто с разных сторон. Просто не везде они дошли до этой условно-идеальной точки, много где остановились на полпути (и вот эти недо-ООП и недо-ФП, увы, многие принимают за эталон). Ну, это моё слабокомпетентное мнение. Могу ошибаться.
                                    +2
                                    Согласно ФП программа будет представлять собой комбинацию функций. Данные в программе будут неизменяемые. Чистая функция не не производит ни каких внешних эффектов, не меняет состояние переменных, просто получает на вход данные и вычисляет результат. Любой вызов функции с одними и теми же переменными приведет к одному и тому же результату, результат вычиления функции зависит только от входных аргументов, но не от внешнего состояния программы.

                                    В ООП программа будет представлять собой комбинацию объектов. Поля объектов хранят его внутреннее состояние. Методы содержат логику поведения объекта — изменения внутреннего состояния и получения доступа к нему. Объекты вызывают методы друг друга динамично меняя свое состояние.

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

                                    Scala поддерживает оба стиля. Их можно смешивать, часть программы написать в одном стиле, часть в другом, выбирая наиболее удобный для конкретной задачи. Или просто вставить в класс несколько чистых функций, реализовав с помощью ФП какие-то сложные вычисления.
                                      0
                                      Разве всё это разделение не рушится, когда мы вспоминаем, что в реальном мире существуют указатели и внешняя среда (в частности ОС)?

                                      И тогда мы приходим к средующему обобщению: у функции в общем случае могут быть внешние эффекты, просто зона появления этих эффектов может быть ограничена (в более продуманном языке — самой сигнатурой функции, в менее продуманном — увы, лишь документацией функции), в том числе аж до нуля (т.н. «чистая» функция), а может быть не ограничена (в худшем случае, когда функция воздействует наружу программы, например, в ОС, т.о. зоны внешних эффектов таких функций мы уже не можем разграничить).
                                        0
                                        Чистые фукции без побочных эффектов имеют целый ряд преимуществ. Их легко тестировать, достаточно сравнить результат с эталоном, окружение не нужно готовить до и очищать после теста. На уровне среды исполнения можно легко реализовать ленивые отложенные вычисления (вычислять функцию только тогда, когда нужен ее результат). Кеширование становится проще. Порядок вычисления функций не имеет значения: в выражении a(x) + b(x) не важно, какую из функций a или b вычислить первой. Компиляторы могут использовать это свойство для оптимизации кода программы. Программы в функциональном стиле проще для понимания, при их анализе не нужно учитывать текущее состояние среды.

                                        При столкновении с реальным миром эта красивая теория конечно рушится. Пользовательский ввод/вывод, работа с БД, аппаратной частью связаны с побочными эффектами. В чисто функциональных языках эту проблему пытаются обходить с помощью разных хитрых трюков по типу монад. В некоторых случаях бывает, что усилия по сохранению чистоты функции создают такую сложность, что проще работать с обычными «грязными» функциями.

                                        Но «слить» чистые функции с грязными на теоретическом уровне не получится. Появление побочных эффектов убивает все преимущества чистых функий.
                                          0
                                          Чистые фукции без побочных эффектов имеют целый ряд преимуществ.
                                          Так кто ж спорит-то…

                                          При столкновении с реальным миром эта красивая теория конечно рушится.
                                          Частично.

                                          Но «слить» чистые функции с грязными на теоретическом уровне не получится. Появление побочных эффектов убивает все преимущества чистых функий.
                                          Мне кажется, всё немного проще. Достаточно позволить функции быть нечистой, но заставить в объявлении функции указывать максимально возможную зону нечистых проявлений. Увы, я знаю не так много языков, которые позволяют делать это качественно.
                                            0
                                            Если честно, я не уловил идею с максимальной зоной нечистых проявлений. Можете привести пример?

                                            Функция считается чистой, если вычисление зависит только от значений входных аргументов, и она не меняет состояние среды. Если функция считывает какие-то значения из памяти, оборудования, базы данных, откуда угодно кроме входных аргументов, то есть вероятность, что при следующем вызове с теми же аргументами она вернет другой результат. Абсолютно не важно, что на это повлияет, и из какого слоя появилась «нечистота». Результат начинает зависеть от последовательности вызовов функций.

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

                          Но если уж пошла речь про JVM-based языки и сахарные плюшки, то почему не Kotlin?

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

                            Если вам для андроида — то да, котлин пойдет лучше, без вопросов. А если нет — то скажем опять же лично для меня у котлина нет особых преимуществ перед старым-престарым груви. И перед скалой. Не вообще нет — а достаточно существенных, чтобы перейти.
                              +4
                              нет особых преимуществ перед старым-престарым груви

                              Статическая типизация. Для неокрепшего (и не только) мозга это серьезная помощь в написании программы.
                              И перед скалой

                              Более простой синтаксис, отсутствие мощных (и непростых для понимания) концепций «в шкафу».
                                0
                                >Статическая типизация.
                                Пардон, но у груви тоже статическая. Ну, точнее так: Apache Groovy is a powerful, optionally typed and dynamic language, with static-typing and static compilation capabilities. Ну то есть, если хотите — то все у вас будет.

                                >Более простой синтаксис,
                                Ну, возможно, но можем рассмотреть на примере. Я бы сказал, что если не лезть вглубину, то вы не заметите разницы. Ну то есть, она конечно будет, и наличие сложных конценций будет тоже, но на мой взгляд это решаемо.
                                  +1
                                  Ну то есть, если хотите — то все у вас будет

                                  Ключевое слово «если захотите». Если захотите, то и на Scala можно без имплиситов и линз. Напоминаю, что с языком сталкивается новичок. А на грувях статическая типизация не прибита гвоздями, в отличие от того же Котлина.
                                    –1
                                    Ну однако же мне никогда за 15 лет это не мешало. При том что я люблю статическую типизацию и пользуюсь ей. Никаких сверхусилий ее применение не требует вообще.
                                      –1
                                      А на грувях статическая типизация не прибита гвоздями, в отличие от того же Котлина.
                                      И это скорее преимущество.
                              +1
                              Первый язык должен давать за какое-то более-менее константное время возможность потрогать и увидеть его результат — простенькая веб-страничка с туду-списком или какой-то простенькие формочки с кнопочками или хотя бы бот для мессенджера. Если же у языка не особо развита экосистема, или она основывается на какой-то другой экосистеме (scala, fsharp), что больше приходится читать доки для основного языка этой экосистемы, то будь там хоть трижды самые лучшие в мире языковые конструкции и решения, это будет плохим выбором для первого языка.
                                0
                                То что у вас есть экосистема (одна из самых богатых) — это замечательно. Вам не нужно писать всякую фигню, она уже лет 15 как написана. У нас еще поверх JVM имеется хадуп и спарк — и как-то ничего, не испытываем никаких проблем, наоборот, скала замечательно приживается. Среди непрограммистов в том числе.
                                  +1
                                  Простенькую веб-страничку с туду-списком на скале можно написать, используя вполне «эндемичные» для неё Akka и Play, например.
                                  +3
                                  При всем уважении к Scala, выбирать его в качестве первого языка стоит аккуратно. Есть вероятность, что для кого-то он может стать и последним языком программирования.
                                    0
                                    Не, ну это без сомнения. Есть преимущества, есть недостатки явные, есть менее явные. Вопрос зарплат тонкий — есть ниши (BigData), где все хорошо, есть прочие ниши, где скорее нет.
                                      +3
                                      Я не про зарплаты, это ирония была про то, что язык может своей сложностью и высоким порогом вхождения может отбить желание программировать дальше.
                                        0
                                        Ну да, такое имеет место (может иметь), но тут все зависит от целей, ради которых вы его изучаете. Что аккуратно — тут вообще без вопросов. Но я просто пробовал на непрофессионалах — аналитиках, в целом каких-то непреодолимых проблем не встречается. Можно выбрать для себя подмножество (а лучше бы кто-то более опытный выбрал) — и в его рамках вполне жить достаточно долго.
                                          0

                                          Это замечательно когда вы программируете для души, вы можете себе выбрать подмножество. Но что будет если этот новичок(в программировании вообще) придет в команду скалистов, и столкнётся с горой придвинутых конструкций, может столкнуться с cats и так далее. Продолжит ли он его любить?

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

                                              А вот выучил я подмножество scala и как мне двигаться дальше? Постепенно изучать оставшееся подмножетсво на хобби проектах? Так можно, но этот путь будет сильно длинным и где брать наставников на это время. В случае с java наставниками выступали коллеги.

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

                                                Не вижу разницы.
                                                Джава простая, но на ней могут реализовать кучу довольно сложных и неочевидных для новичка штук с аннотациями, кодогенерацией, тестами, библиотечками для dependency injection или вообще энтерпрайз фреймворками. Вам придётся их осваивать.
                                                В скале аналогично, просто язык сложнее и гибче, и некоторые внешние библиотеки за счёт этого получаются проще. Та же cats хороша тем, что она общая для разных кодовых баз, и при переходе на другую работу вам не придётся осваивать всё заново.

                                                  +1
                                                  >Тогда тем более не понятно зачем его учить как первый язык.
                                                  Ну смотрите, я это в общем не предлагал. Я это пробовал, но не учить по факту как первому языку — у меня просто нет таких подопытных кроликов. Я учил аналитиков, они не профессиональные программисты. Но языки какие-то знают. И в общем, все проходит достаточно спокойно, при том что у нас не было в общем-то систематических занятий.

                                                  Т.е. то что порог крутой — ну это с какой стороны зайти, на уровне скажем переменных, констант, вещей типа if, функций, коллекций и т.п. некоторые вещи наоборот проще. Оне не обязательно такие же — после java скажем регулярки у вас поначалу могут вызвать недопонимание.

                                                  Ну так, в качестве примера — попробуйте в java сделать стрим по массиву. И попробуйте в скале. У массива в java нет методов stream(), ну и дальше нет .map, .filter и т.п. — это все можно, но с некими приседаниями. Несложными. Массив — это такая кривая коллекция. Специальная. Которая усложняет жизнь.

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

                                                  И еще я пожалуй присоединюсь к комменту ниже. У вас и в java такие же неочевидные моменты будут. И путь может быть длинным. Просто конечная точка будет разная.
                                      +1
                                      Вангую, что Scala 3 тоже не взлетит:
                                      — новых ниш, где она была бы явно востребована пока нет;
                                      — в старых нишах хорошо себя чувствуют другие ЯП, которые оптимальны для них по набору своих сильных и слабых сторон;
                                      — весь интерес к ней — это просто желание разработчиков к чему-то новому, но так как все ЯП развиваются, то в них тоже можно удовлетворять свое любопытство;
                                      — мало вакансий даже на прежних версиях Скалы.

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

                                      А так даже приятно, что люди с такими серьезными лицами фаном занимаются…
                                        +1
                                        Вангую, что Scala 3 тоже не взлетит:

                                        Даже если и не взлетит, возможно, заложенные идеи перетекут в другие языки. Если бы в свое время не появились Groovy, Scala, Clojure, кто знает сколько бы еще ждали в Java лямбд и Stream API. А сейчас в Java уже и var и аналоги case классов и чуть ли не паттернматчинг.
                                        +1

                                        Статья очень интересная.
                                        Спасибо.

                                          +2
                                          Я тот самый новичок. Из языков программирования — Basic в школе и Delphi в институте, дальше всякие вспомогательные скриптовые мелочи.
                                          Честно прочитал статью, но так и не понял, почему стоит браться за Scala. Вижу много умных слов, но не понимаю, что за ними стоит. А те, что понимаю, не кажутся мне важными. Долгая компиляция? Ну, вряд ли ближайшие пару лет меня это как-то коснётся — хеллоуворлд скомпилируется в приемлемое время. То же самое касается и производительности.
                                          Быстрые изменения? Значит, то, что я сейчас с таким усердием учу, завтра будет неактуально. Типизация и ООП? Да-да, я помню, TForm1.Button1Click…
                                          А все остальные разделы помечены как «не для новичков», и я там ожидаемо мало что понял.

                                          Так чем же хорош Scala именно как первый язык?
                                            0
                                            У всех по разному воспринимается первый язык, скажем так, зависит от усидчивости. Если хватит терпения на scala, c++ или rust то можно начинать с них. потому что языки богаты на возможности. Но для большинства желательно язык который дает быстрый результат, чтобы подстегнуть интерес. Большинство просто забросит язык в котором нужно месяц разбираться чтобы сделать что то не из туториала. А программисту все равно нужны выучить все парадигмы и попробовать, а в одном языке их не собрать. Так что да, динамически типизированный и декларативный язык тоже нужно попробовать.
                                              0
                                              я бы посоветовал пройти несколько первых уроков курса Мартина Одерски, когда он обновит его до новой версии языка. Даже если вы не будете программировать на скале, это даст вам неплохую базу в функциональном программировании
                                                +1
                                                Мой комментарий не про то, как выучить Scala. Он про то, что из статьи я так и не понял, почему мне стоит учить Scala как первый язык.
                                                  0
                                                  для вас я напишу специальный текст «Почему мне стоит учить Scala», без DOT и умных слов. Просто это будет не хабровский формат и я выложу его куда-нибудь в другое место, а здесь дам ссылку.

                                                  Если коротко, то Scala — это возможность научиться функциональному программированию на безопасном языке, у которого есть большое будущее
                                              0
                                              Если нужно ФП на JVM:

                                              www.braveclojure.com/foreword

                                              'nuff said.
                                                0

                                                Лучше Eta.

                                                  0
                                                  а оно живое ещё?
                                                    0

                                                    Вроде шевелится. Это Frege умер.

                                                +1
                                                У вас ошибка в примере, нужно:
                                                println(new Stack().push("hello").push(new Object()).push(7))
                                                

                                                Это же не Case классы.
                                                  0
                                                  В Scala 3 точно можно без new.
                                                    +1
                                                    я очень ждал этого комментария от внимательного читателя.

                                                    на самом деле в третьей скале можно уже не писать new
                                                      0
                                                      Кстати, насколько она уже жизнеспособна на ваш взгляд?
                                                        0
                                                        более чем жизнеспобна по-моему.

                                                        это то, какой она должна была быть с самого начала
                                                          0
                                                          >с самого начала
                                                          Ну, с самого начала обычно сложно предсказать, что на самом деле важно. Вот я скажем сижу сейчас на 2.11.8, примерно, потому что у меня спарк с ней собран, и совместимости нет. При этом я легко могу себе вообразить проект, для которого это вообще не проблема — пересобрали и в путь. Но пересобрать спарк, размер кодовой базы которого на порядок-другой больше, чем у типового своего проекта — это такое развлечение, которым вряд ли кто-то будет заниматься.
                                                    +1
                                                    Функциональное программирование — это многообещающая тенденция. Скале она присуща в не меньшей степени чем ООП, и они взаимно обогащают друг друга благодаря этому языку. Рискну предположить, что скала — первый язык промышленного уровня с такими свойствами.

                                                    Разумеется не первый. Задолго до Scala вполне существовали подобные языки. Из тех что я знаю, это Common Lisp (CLOS) и Ocaml (диалект ML с элементами ООП). Если верить википедии, то эти языки повлияли на Scala. Также многие реализации языка Scheme имеют поддержку ООП, но это не определено в стандарте языка (например GNU Guile).

                                                    Мало какой язык может похвастать математически точным исчислением, лежащем в его основе.

                                                    Опять же из списка языков, которые повлияли на Scala. Standard ML и Scheme. Оба имеют формальную спецификацию. Но да, таких языков действительно мало.

                                                      +1
                                                      В написанной вами цитате вы, кажется, игнорируете фразу «промышленного уровня».

                                                      Язык-то далеко не первый, это правда, но мне кажется (и, видимо, автору тоже), что он получил заметно больше распространения в «широком IT», чем упомянутые вами языки. Так ли это на самом деле — не знаю, но впечатление такое есть. Фраза «рискну предположить» в этом смысле вполне честный disclaimer.
                                                        0
                                                         А Common Lisp (CLOS) и Ocaml — это точно enterprise-языки?
                                                          0
                                                          Ocaml точно
                                                        0

                                                        К сожалению про Scala не знаю ничего — но беглый взгляд на код с обилием case и else наводит на мысль что до "языка будущего" еще очень далеко. Даже в C# уже давно используют словари ...

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

                                                        Самое читаемое