Skip to content

Add contextual abstraction in ru #2868

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 3 commits into from
Jul 31, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
30 changes: 22 additions & 8 deletions _includes/version-specific-notice.html
Original file line number Diff line number Diff line change
Expand Up @@ -2,15 +2,29 @@
<blockquote class="help-info">
<i class="fa fa-info"></i><span style="margin-left: 0.5rem">
{% if include.language == 'scala3' %}
This doc page is specific to Scala 3,
and may cover new concepts not available in Scala 2. Unless
otherwise stated, all the code examples in this page assume
you are using Scala 3.
{% if include.page-language == 'ru' %}
Эта страница документа относится к Scala 3 и
может охватывать новые концепции, недоступные в Scala 2.
Если не указано явно, все примеры кода на этой странице
предполагают, что вы используете Scala 3.
{% else %}
This doc page is specific to Scala 3,
and may cover new concepts not available in Scala 2. Unless
otherwise stated, all the code examples in this page assume
you are using Scala 3.
{% endif %}
{% else if include.language == 'scala2' %}
This doc page is specific to features shipped in Scala 2,
which have either been removed in Scala 3 or replaced by an
alternative. Unless otherwise stated, all the code examples
in this page assume you are using Scala 2.
{% if include.page-language == 'ru' %}
Эта страница документа относится к функциям, представленным в Scala 2,
которые либо были удалены в Scala 3, либо заменены альтернативными.
Если не указано явно, все примеры кода на этой странице предполагают,
что вы используете Scala 2.
{% else %}
This doc page is specific to features shipped in Scala 2,
which have either been removed in Scala 3 or replaced by an
alternative. Unless otherwise stated, all the code examples
in this page assume you are using Scala 2.
{% endif %}
{% endif %}
</span>
</blockquote>
Expand Down
7 changes: 6 additions & 1 deletion _layouts/multipage-overview.html
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,12 @@
{% else if page.scala2 %}
{% assign versionSpecificLang = 'scala2' %}
{% endif %}
{% include version-specific-notice.html language=versionSpecificLang %}
{% if page.language %}
{% assign pageLanguage = page.language %}
{% else %}
{% assign pageLanguage = 'en' %}
{% endif %}
{% include version-specific-notice.html language=versionSpecificLang page-language=pageLanguage %}
{% endif %}
<noscript>
<blockquote>
Expand Down
2 changes: 1 addition & 1 deletion _overviews/scala3-book/ca-contextual-abstractions-intro.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
title: Contextual Abstractions
type: chapter
description: This chapter provides an introduction to the Scala 3 concept of Contextual Abstractions.
languages: [zh-cn]
languages: [ru, zh-cn]
num: 59
previous-page: types-others
next-page: ca-extension-methods
Expand Down
2 changes: 1 addition & 1 deletion _overviews/scala3-book/ca-extension-methods.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
title: Extension Methods
type: section
description: This page demonstrates how Extension Methods work in Scala 3.
languages: [zh-cn]
languages: [ru, zh-cn]
num: 60
previous-page: ca-contextual-abstractions-intro
next-page: ca-context-parameters
Expand Down
96 changes: 96 additions & 0 deletions _ru/scala3/book/ca-contextual-abstractions-intro.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
---
layout: multipage-overview
title: Контекстные абстракции
scala3: true
partof: scala3-book
overview-name: "Scala 3 — Book"
type: chapter
description: В этой главе представлено введение в концепцию контекстных абстракций Scala 3.
language: ru
num: 59
previous-page: types-others
next-page: ca-extension-methods
---

## Предпосылка

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

- реализация тайп классов (_type classes_)
- установление контекста
- внедрение зависимости (_dependency injection_)
- выражение возможностей
- вычисление новых типов и доказательство взаимосвязей между ними

В этом отношении Scala оказала влияние на другие языки. Например, трейты в Rust или protocol extensions Swift.
Предложения по дизайну также представлены для Kotlin в качестве разрешения зависимостей во время компиляции,
для C# в качестве Shapes и Extensions или для F# в качестве Traits.
Контекстные абстракции также являются общей особенностью средств доказательства теорем, таких как Coq или Agda.

Несмотря на то, что в этих проектах используется разная терминология,
все они являются вариантами основной идеи вывода терминов (term inference):
учитывая тип, компилятор синтезирует "канонический" термин, который имеет этот тип.

## Редизайн в Scala 3

В Scala 2 контекстные абстракции поддерживаются пометкой `implicit` определений (методов и значений) или параметров
(см. [Параметры контекста]({% link _overviews/scala3-book/ca-context-parameters.md %})).

Scala 3 включает в себя переработку контекстных абстракций.
Хотя эти концепции постепенно "открывались" в Scala 2, теперь они хорошо известны и понятны, и редизайн использует эти знания.

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

- **Расширение классов задним числом**.
В Scala 2 методы расширения должны были кодироваться с использованием [неявных преобразований][implicit-conversions] или [неявных классов]({% link _overviews/core/implicit-classes.md %}).
Напротив, в Scala 3 [методы расширения][extension-methods] теперь встроены непосредственно в язык, что приводит к улучшению сообщений об ошибках и улучшению вывода типов.

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

- **Предоставление экземпляров тайп-классов**.
[Given экземпляры][givens] позволяют программистам определять _каноническое значение_ определенного типа.
Это делает программирование с [тайп-классами][type-classes] более простым без утечек деталей реализации.

- **Неявное преобразование одного типа в другой**.
Неявное преобразование было [переработано с нуля][implicit-conversions] как экземпляры тайп-класса `Conversion`.

- **Контекстные абстракции высшего порядка**.
_Совершенно новая_ функция [контекстных функций][contextual-functions] делает контекстные абстракции объектами первого класса.
Они являются важным инструментом для авторов библиотек и позволяют выражать лаконичный DSL.

- **Полезная обратная связь от компилятора**.
Если компилятор не может разрешить неявный параметр, теперь он предлагает [предложения по импорту](https://www.scala-lang.org/blog/2020/05/05/scala-3-import-suggestions.html), которые могут решить проблему.

## Преимущества

Эти изменения в Scala 3 обеспечивают лучшее разделение вывода терминов от остального языка:

- существует единственный способ определить данные
- существует единственный способ ввести неявные параметры и аргументы
- существует отдельный способ [импорта givens][given-imports], который не позволяет им прятаться в море обычного импорта
- существует единственный способ определить [неявное преобразование][implicit-conversions], которое четко обозначено как таковое и не требует специального синтаксиса

К преимуществам этих изменений относятся:

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

В этой главе в следующих разделах представлены многие из этих новых функций.

[givens]: {% link _overviews/scala3-book/ca-context-parameters.md %}
[given-imports]: {% link _overviews/scala3-book/ca-given-imports.md %}
[implicit-conversions]: {% link _overviews/scala3-book/ca-implicit-conversions.md %}
[extension-methods]: {% link _overviews/scala3-book/ca-extension-methods.md %}
[context-bounds]: {% link _overviews/scala3-book/ca-context-bounds.md %}
[type-classes]: {% link _overviews/scala3-book/ca-type-classes.md %}
[equality]: {% link _overviews/scala3-book/ca-multiversal-equality.md %}
[contextual-functions]: {{ site.scala3ref }}/contextual/context-functions.html
145 changes: 145 additions & 0 deletions _ru/scala3/book/ca-extension-methods.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,145 @@
---
layout: multipage-overview
title: Методы расширения
scala3: true
partof: scala3-book
overview-name: "Scala 3 — Book"
type: section
description: В этой главе представлена работа методов расширения в Scala 3.
language: ru
num: 60
previous-page: ca-contextual-abstractions-intro
next-page:
versionSpecific: true
---

В Scala 2 аналогичного результата можно добиться с помощью [неявных классов]({% link _overviews/core/implicit-classes.md %}).

---

Методы расширения позволяют добавлять методы к типу после того, как он был определен,
т.е. они позволяют добавлять новые методы в закрытые классы.
Например, представьте, что кто-то создал класс `Circle`:

{% tabs ext1 %}
{% tab 'Scala 2 и 3' %}

```scala
case class Circle(x: Double, y: Double, radius: Double)
```

{% endtab %}
{% endtabs %}

Теперь представим, что необходим метод `circumference`, но нет возможности изменить исходный код `Circle`.
До того как концепция вывода терминов была введена в языки программирования,
единственное, что можно было сделать, это написать метод в отдельном классе или объекте, подобном этому:

{% tabs ext2 class=tabs-scala-version %}
{% tab 'Scala 2' %}

```scala
object CircleHelpers {
def circumference(c: Circle): Double = c.radius * math.Pi * 2
}
```

{% endtab %}
{% tab 'Scala 3' %}

```scala
object CircleHelpers:
def circumference(c: Circle): Double = c.radius * math.Pi * 2
```

{% endtab %}
{% endtabs %}

Затем этот метод можно было использовать следующим образом:

{% tabs ext3 %}
{% tab 'Scala 2 и 3' %}

```scala
val aCircle = Circle(2, 3, 5)

// без использования метода расширения
CircleHelpers.circumference(aCircle)
```

{% endtab %}
{% endtabs %}

Но методы расширения позволяют создать метод `circumference` для работы с экземплярами `Circle`:

{% tabs ext4 %}
{% tab 'Только в Scala 3' %}

```scala
extension (c: Circle)
def circumference: Double = c.radius * math.Pi * 2
```

{% endtab %}
{% endtabs %}

В этом коде:

- `Circle` — это тип, к которому будет добавлен метод расширения `circumference`
- Синтаксис `c: Circle` позволяет ссылаться на переменную `c` в методах расширения

Затем в коде метод `circumference` можно использовать так же, как если бы он был изначально определен в классе `Circle`:

{% tabs ext5 %}
{% tab 'Только в Scala 3' %}

```scala
aCircle.circumference
```

{% endtab %}
{% endtabs %}

### Импорт методов расширения

Представим, что `circumference` определен в пакете `lib` - его можно импортировать с помощью

{% tabs ext6 %}
{% tab 'Только в Scala 3' %}

```scala
import lib.circumference

aCircle.circumference
```

{% endtab %}
{% endtabs %}

Если импорт отсутствует, то компилятор выводит подробное сообщение об ошибке, подсказывая возможный импорт, например так:

```text
value circumference is not a member of Circle, but could be made available as an extension method.

The following import might fix the problem:

import lib.circumference
```

## Обсуждение

Ключевое слово `extension` объявляет о намерении определить один или несколько методов расширения для типа, заключенного в круглые скобки.
Чтобы определить для типа несколько методов расширения, используется следующий синтаксис:

{% tabs ext7 %}
{% tab 'Только в Scala 3' %}

```scala
extension (c: Circle)
def circumference: Double = c.radius * math.Pi * 2
def diameter: Double = c.radius * 2
def area: Double = math.Pi * c.radius * c.radius
```

{% endtab %}
{% endtabs %}
1 change: 1 addition & 0 deletions _ru/scala3/book/types-adts-gadts.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ language: ru
num: 53
previous-page: types-union
next-page: types-variance
versionSpecific: true
---

<span class="tag tag-inline">Только в Scala 3</span>
Expand Down
2 changes: 1 addition & 1 deletion _ru/scala3/book/types-others.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ description: В этом разделе упоминаются другие ра
language: ru
num: 58
previous-page: types-dependent-function
next-page:
next-page: ca-contextual-abstractions-intro
---

В Scala есть несколько других расширенных типов, которые не показаны в этой книге, в том числе:
Expand Down
3 changes: 1 addition & 2 deletions _ru/scala3/book/types-union.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,10 +10,9 @@ language: ru
num: 52
previous-page: types-intersection
next-page: types-adts-gadts
versionSpecific: true
---

<span class="tag tag-inline">Только в Scala 3</span>

Используемый для типов `|` оператор создает так называемый _тип объединения_ (_union type_).
Тип `А | B` представляет значения, которые относятся **либо** к типу `A`, **либо** к типу `B`.

Expand Down