Предпосылка
Контекстные абстракции — это способ абстрагироваться от контекста. Они представляют собой единую парадигму с большим разнообразием вариантов использования, среди которых:
- реализация тайп классов (type classes)
- установление контекста
- внедрение зависимости (dependency injection)
- выражение возможностей
- вычисление новых типов и доказательство взаимосвязей между ними
В этом отношении Scala оказала влияние на другие языки. Например, трейты в Rust или protocol extensions Swift. Предложения по дизайну также представлены для Kotlin в качестве разрешения зависимостей во время компиляции, для C# в качестве Shapes и Extensions или для F# в качестве Traits. Контекстные абстракции также являются общей особенностью средств доказательства теорем, таких как Coq или Agda.
Несмотря на то, что в этих проектах используется разная терминология, все они являются вариантами основной идеи вывода терминов (term inference): учитывая тип, компилятор синтезирует “канонический” термин, который имеет этот тип.
Редизайн в Scala 3
В Scala 2 контекстные абстракции поддерживаются пометкой implicit
определений (методов и значений) или параметров
(см. Параметры контекста).
Scala 3 включает в себя переработку контекстных абстракций. Хотя эти концепции постепенно “открывались” в Scala 2, теперь они хорошо известны и понятны, и редизайн использует эти знания.
Дизайн Scala 3 фокусируется на намерении, а не на механизме. Вместо того, чтобы предлагать одну очень мощную функцию имплицитов, Scala 3 предлагает несколько функций, ориентированных на варианты использования:
-
Расширение классов задним числом. В Scala 2 методы расширения должны были кодироваться с использованием неявных преобразований или неявных классов. Напротив, в Scala 3 методы расширения теперь встроены непосредственно в язык, что приводит к улучшению сообщений об ошибках и улучшению вывода типов.
-
Абстрагирование контекстной информации. Предложения Using позволяют программистам абстрагироваться от информации, которая доступна в контексте вызова и должна передаваться неявно. В качестве улучшения по сравнению со Scala 2 подразумевается, что предложения using могут быть указаны по типу, освобождая сигнатуры функций от имен переменных, на которые никогда не ссылаются явно.
-
Предоставление экземпляров тайп-классов. Given экземпляры позволяют программистам определять каноническое значение определенного типа. Это делает программирование с тайп-классами более простым без утечек деталей реализации.
-
Неявное преобразование одного типа в другой. Неявное преобразование было переработано с нуля как экземпляры тайп-класса
Conversion
. -
Контекстные абстракции высшего порядка. Совершенно новая функция контекстных функций делает контекстные абстракции объектами первого класса. Они являются важным инструментом для авторов библиотек и позволяют выражать лаконичный DSL.
-
Полезная обратная связь от компилятора. Если компилятор не может разрешить неявный параметр, теперь он предлагает предложения по импорту, которые могут решить проблему.
Преимущества
Эти изменения в Scala 3 обеспечивают лучшее разделение вывода терминов от остального языка:
- существует единственный способ определить данные
- существует единственный способ ввести неявные параметры и аргументы
- существует отдельный способ импорта givens, который не позволяет им прятаться в море обычного импорта
- существует единственный способ определить неявное преобразование, которое четко обозначено как таковое и не требует специального синтаксиса
К преимуществам этих изменений относятся:
- новый дизайн позволяет избежать взаимодействия функций и делает язык более согласованным
- implicits становятся более легкими для изучения и более сложными для злоупотреблений
- значительно улучшается ясность 95% программ Scala, использующих implicits
- есть потенциал, чтобы сделать вывод термов однозначным способом, который также доступен и удобен.
В этой главе в следующих разделах представлены многие из этих новых функций.
Contributors to this page:
Contents
- Введение
- Возможности Scala
- Почему Scala 3?
- Почувствуй Scala
- Пример 'Hello, World!'
- REPL
- Переменные и типы данных
- Структуры управления
- Моделирование данных
- Методы
- Функции первого класса
- Одноэлементные объекты
- Коллекции
- Контекстные абстракции
- Верхнеуровневые определения
- Обзор
- Первый взгляд на типы
- Интерполяция строк
- Структуры управления
- Моделирование предметной области
- Инструменты
- Моделирование ООП
- Моделирование ФП
- Методы
- Особенности методов
- Main методы в Scala 3
- Обзор
- Функции
- Анонимные функции
- Параметры функции
- Eta расширение
- Функции высшего порядка
- Собственный map
- Создание метода, возвращающего функцию
- Обзор
- Пакеты и импорт
- Коллекции в Scala
- Типы коллекций
- Методы в коллекциях
- Обзор
- Функциональное программирование
- Что такое функциональное программирование?
- Неизменяемые значения
- Чистые функции
- Функции — это значения
- Функциональная обработка ошибок
- Обзор
- Типы и система типов
- Определение типов
- Параметризованные типы
- Пересечение типов
- Объединение типов
- Алгебраические типы данных
- Вариантность
- Непрозрачные типы
- Структурные типы
- Зависимые типы функций
- Другие типы
- Контекстные абстракции
- Методы расширения
- Параметры контекста
- Контекстные границы
- Given импорты
- Классы типов
- Многостороннее равенство
- Неявное преобразование типов
- Обзор
- Параллелизм
- Scala утилиты
- Сборка и тестирование проектов Scala с помощью Sbt
- Рабочие листы
- Взаимодействие с Java