Новое в Scala 3

Language

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

Что нового Scala 3

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

Новое и яркое: синтаксис

Помимо многих (незначительных) чисток, синтаксис Scala 3 предлагает следующие улучшения:

Последовательное: контекстуальные абстракции

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

  • Абстрагирование контекстной информации. Using предложения позволяют программистам абстрагироваться от информации, которая доступна в контексте вызова и должна передаваться неявно. В качестве улучшения по сравнению с имплицитами в Scala 2 предложения using могут указываться по типу, освобождая сигнатуры функций от имен переменных, если на них не ссылаются явно.

  • Предоставление экземпляров классов типов. Экземпляры given позволяют программистам определять каноническое значение определенного типа. Это делает программирование с классами типов более простым без распространения деталей реализации.

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

  • Просмотр одного типа как другого. Неявные преобразования между типами были переработаны с нуля как экземпляры класса типов Conversion.

  • Высокоуровневые контекстные абстракции. Совершенно новая особенность контекстных функций делает контекстные абстракции функциями первого класса. Они являются важным инструментом для авторов библиотек и позволяют кратко выражать предметно-ориентированные языки.

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

Говори, что имеешь в виду: улучшения системы типов

Помимо значительно улучшенного вывода типов, система типов Scala 3 также предлагает множество новых функций, предоставляя вам мощные инструменты для статического выражения инвариантов в типах:

  • Перечисления. Enums были переработаны, чтобы хорошо сочетаться с case-классами и формировать новый стандарт для выражения алгебраических типов данных.

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

  • Типы пересечения и объединения. Основание системы типов на новом фундаменте привело к введению новых функций системы типов: экземпляры типов-пересечений, например A & B, являются экземплярами обоих типов A и B. Экземпляры типов объединения, например A | B, являются экземплярами либо A, либо B. Обе конструкции позволяют программистам гибко выражать ограничения типов вне иерархии наследования.

  • Зависимые типы функций. Scala 2 уже позволяла возвращаемым типам зависеть от (значения) аргументов. В Scala 3 теперь можно абстрагироваться от этого шаблона и выразить зависимые типы функций. В типе type F = (e: Entry) => e.Key тип результата зависит от аргумента!

  • Полиморфные типы функций. Как и в случае с зависимыми типами функций, Scala 2 поддерживала методы, допускающие параметры типа, но не позволяла программистам абстрагироваться от этих методов. В Scala 3 полиморфные типы функций, например, [A] => List[A] => List[A] могут абстрагироваться от функций, которые принимают аргументы типа в дополнение к своим аргументам значения.

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

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

Переосмысление: объектно-ориентированное программирование

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

  • Передача параметров. Трейты становятся ближе к классам и теперь также могут принимать параметры, что делает их еще более мощным средством модульной декомпозиции программного обеспечения.
  • Планирование расширения. Наследование классов, которые не предназначены для расширения, является давней проблемой объектно-ориентированного проектирования. Чтобы решить эту проблему, открытые классы требуют, чтобы разработчики библиотек явно помечали классы как открытые.
  • Скрытие деталей реализации. Вспомогательные трейты, которые реализуют поведение, иногда не должны быть частью вывода типов. В Scala 3 эти трейты могут быть помечены как прозрачные, скрывающие наследование от пользователя (в выводимых типах).
  • Композиция над наследованием. Эта фраза часто цитируется, но утомительна для реализации. Не так обстоит дело с export предложениями в Scala 3 : симметричные по отношению к импорту, предложения export позволяют пользователю определять псевдонимы для выбранных членов объекта.
  • Больше никаких NullPointerException (экспериментально). Scala 3 безопаснее, чем когда-либо: явное значение null выводит null из иерархии типов, помогая статически отлавливать ошибки; дополнительные проверки для безопасной инициализации обнаруживают попытки доступа к неинициализированным объектам.

Зарядка в комплекте: метапрограммирование

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

  • Inline. В качестве базовой отправной точки функция inline позволяет редуцировать значения и методы во время компиляции. Эта простая функция уже охватывает множество вариантов использования и в то же время обеспечивает отправную точку для более продвинутых функций.
  • Операции времени компиляции. Пакет scala.compiletime содержит дополнительные функции, которые можно использовать для реализации inline методов.
  • Блоки кода Quoted. В Scala 3 добавлена новая функция квазицитирования кода, обеспечивающая удобный высокоуровневый интерфейс для создания и анализа кода. Создать код для добавления единицы к единице так же просто, как '{ 1 + 1 }.
  • Reflection API. Для более продвинутых вариантов использования quotes.reflect предоставляет более детализированный контроль для проверки и создания деревьев программ.

Если вы хотите узнать больше о метапрограммировании в Scala 3, приглашаем вас пройти наш tutorial.

Contributors to this page: