Skip to content

Commit 8ae9c0a

Browse files
committed
Initialization and Introduction
1 parent c507bcc commit 8ae9c0a

File tree

78 files changed

+15644
-1
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

78 files changed

+15644
-1
lines changed

_config.yml

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -105,6 +105,16 @@ defaults:
105105
overview-name: "Scala 3 — Book"
106106
layout: multipage-overview
107107
permalink: "/scala3/book/:title.html"
108+
-
109+
scope:
110+
path: "_zh-cn/overviews/scala3-book"
111+
values:
112+
scala3: true
113+
partof: scala3-book-zh-cn
114+
type: section
115+
overview-name: "Scala 3"
116+
layout: multipage-overview
117+
permalink: "/zh-cn/scala3/book/:title.html"
108118
-
109119
scope:
110120
path: "_overviews/scala3-migration"

_zh-cn/index.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ scala3-sections:
2222
- title: "Scala 3 书籍"
2323
description: "一部介绍主要语言特性的线上书"
2424
icon: "fa fa-book"
25-
link: /scala3/book/introduction.html
25+
link: /zh-cn/scala3/book/introduction.html
2626
- title: "更多细节"
2727
links:
2828
- title: "迁移指引"
Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
---
2+
title: Context Bounds
3+
type: section
4+
description: This page demonstrates Context Bounds in Scala 3.
5+
num: 61
6+
previous-page: types-type-classes
7+
next-page: ca-given-imports
8+
---
9+
10+
11+
{% comment %}
12+
- TODO: define "context parameter"
13+
- TODO: define "synthesized" and "synthesized arguments"
14+
{% endcomment %}
15+
16+
In many situations the name of a _context parameter_ doesn’t have to be mentioned explicitly, since it’s only used by the compiler in synthesized arguments for other context parameters.
17+
In that case you don’t have to define a parameter name, and can just provide the parameter type.
18+
19+
20+
## Background
21+
22+
For example, this `maximum` method takes a _context parameter_ of type `Ord`, only to pass it on as an argument to `max`:
23+
24+
```scala
25+
def maximum[A](xs: List[A])(using ord: Ord[A]): A =
26+
xs.reduceLeft(max(ord))
27+
```
28+
29+
In that code the parameter name `ord` isn’t actually required; it can be passed on as an inferred argument to `max`, so you just state that `maximum` uses the type `Ord[A]` without giving it a name:
30+
31+
```scala
32+
def maximum[A](xs: List[A])(using Ord[A]): A =
33+
xs.reduceLeft(max)
34+
```
35+
36+
37+
## Context bounds
38+
39+
Given that background, a _context bound_ is a shorthand syntax for expressing the pattern of, “a context parameter that depends on a type parameter.”
40+
41+
Using a context bound, the `maximum` method can be written like this:
42+
43+
```scala
44+
def maximum[A: Ord](xs: List[A]): A = xs.reduceLeft(max)
45+
```
46+
47+
A bound like `: Ord` on a type parameter `A` of a method or class indicates a context parameter with `Ord[A]`.
48+
49+
For more information about context bounds, see the [“What are context bounds?”](https://docs.scala-lang.org/tutorials/FAQ/context-bounds.html) section of the Scala FAQ.
Lines changed: 87 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,87 @@
1+
---
2+
title: Contextual Abstractions
3+
type: chapter
4+
description: This chapter provides an introduction to the Scala 3 concept of Contextual Abstractions.
5+
num: 58
6+
previous-page: types-others
7+
next-page: ca-given-using-clauses
8+
---
9+
10+
11+
## Background
12+
13+
Implicits in Scala 2 were a major distinguishing design feature.
14+
They are *the* fundamental way to abstract over context.
15+
They represent a unified paradigm with a great variety of use cases, among them:
16+
17+
- Implementing type classes
18+
- Establishing context
19+
- Dependency injection
20+
- Expressing capabilities
21+
- Computing new types, and proving relationships between them
22+
23+
Since then, other languages have followed suit, e.g., Rust’s traits or Swift’s protocol extensions.
24+
Design proposals are also on the table for Kotlin as compile time dependency resolution, for C# as Shapes and Extensions or for F# as Traits.
25+
Implicits are also a common feature of theorem provers such as Coq or Agda.
26+
27+
Even though these designs use different terminology, they’re all variants of the core idea of *term inference*:
28+
Given a type, the compiler synthesizes a “canonical” term that has that type.
29+
30+
31+
## Redesign
32+
33+
Scala 3 includes a redesign of contextual abstractions in Scala.
34+
While these concepts were gradually “discovered” in Scala 2, they’re now well known and understood, and the redesign takes advantage of that knowledge.
35+
36+
The design of Scala 3 focuses on **intent** rather than **mechanism**.
37+
Instead of offering one very powerful feature of implicits, Scala 3 offers several use-case oriented features:
38+
39+
- **Abtracting over contextual information**.
40+
[Using clauses][givens] allow programmers to abstract over information that is available in the calling context and should be passed implicitly.
41+
As an improvement over Scala 2 implicits, using clauses can be specified by type, freeing function signatures from term variable names that are never explicitly referred to.
42+
43+
- **Providing Type-class instances**.
44+
[Given instances][type-classes] allow programmers to define the _canonical value_ of a certain type.
45+
This makes programming with type-classes more straightforward without leaking implementation details.
46+
47+
- **Retroactively extending classes**.
48+
In Scala 2, extension methods had to be encoded using implicit conversions or implicit classes.
49+
In contrast, in Scala 3 [extension methods][extension-methods] are now directly built into the language, leading to better error messages and improved type inference.
50+
51+
- **Viewing one type as another**.
52+
Implicit conversion have been [redesigned][implicit-conversions] from the ground up as instances of a type-class `Conversion`.
53+
54+
- **Higher-order contextual abstractions**.
55+
The _all-new_ feature of [context functions][contextual-functions] makes contextual abstractions a first-class citizen.
56+
They are an important tool for library authors and allow to express concise domain specific languages.
57+
58+
- **Actionable feedback from the compiler**.
59+
In case an implicit parameter can not be resolved by the compiler, it now provides you [import suggestions](https://www.scala-lang.org/blog/2020/05/05/scala-3-import-suggestions.html) that may fix the problem.
60+
61+
62+
## Benefits
63+
64+
These changes in Scala 3 achieve a better separation of term inference from the rest of the language:
65+
66+
- There’s a single way to define givens
67+
- There’s a single way to introduce implicit parameters and arguments
68+
- There’s a separate way to [import givens][given-imports] that does not allow them to hide in a sea of normal imports
69+
- There’s a single way to define an [implicit conversion][implicit-conversions], which is clearly marked as such, and does not require special syntax
70+
71+
Benefits of these changes include:
72+
73+
- The new design thus avoids feature interactions and makes the language more consistent
74+
- It makes implicits easier to learn and harder to abuse
75+
- It greatly improves the clarity of the 95% of Scala programs that use implicits
76+
- It has the potential to enable term inference in a principled way that is also accessible and friendly
77+
78+
This chapter introduces many of these new features in the following sections.
79+
80+
[givens]: {% link _overviews/scala3-book/ca-given-using-clauses.md %}
81+
[given-imports]: {% link _overviews/scala3-book/ca-given-imports.md %}
82+
[implicit-conversions]: {% link _overviews/scala3-book/ca-implicit-conversions.md %}
83+
[extension-methods]: {% link _overviews/scala3-book/ca-extension-methods.md %}
84+
[context-bounds]: {% link _overviews/scala3-book/ca-context-bounds.md %}
85+
[type-classes]: {% link _overviews/scala3-book/ca-type-classes.md %}
86+
[equality]: {% link _overviews/scala3-book/ca-multiversal-equality.md %}
87+
[contextual-functions]: {% link _overviews/scala3-book/types-dependent-function.md %}
Lines changed: 85 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,85 @@
1+
---
2+
title: Extension Methods
3+
type: section
4+
description: This page demonstrates how Extension Methods work in Scala 3.
5+
num: 63
6+
previous-page: ca-given-imports
7+
next-page: ca-type-classes
8+
---
9+
10+
11+
Extension methods let you add methods to a type after the type is defined, i.e., they let you add new methods to closed classes.
12+
For example, imagine that someone else has created a `Circle` class:
13+
14+
```scala
15+
case class Circle(x: Double, y: Double, radius: Double)
16+
```
17+
18+
Now imagine that you need a `circumference` method, but you can’t modify their source code.
19+
Before the concept of term inference was introduced into programming languages, the only thing you could do was write a method in a separate class or object like this:
20+
21+
```scala
22+
object CircleHelpers:
23+
def circumference(c: Circle): Double = c.radius * math.Pi * 2
24+
```
25+
26+
Then you’d use that method like this:
27+
28+
```scala
29+
val aCircle = Circle(2, 3, 5)
30+
31+
// without extension methods
32+
CircleHelpers.circumference(aCircle)
33+
```
34+
35+
But with extension methods you can create a `circumference` method to work on `Circle` instances:
36+
37+
```scala
38+
extension (c: Circle)
39+
def circumference: Double = c.radius * math.Pi * 2
40+
```
41+
42+
In this code:
43+
44+
- `Circle` is the type that the extension method `circumference` will be added to
45+
- The `c: Circle` syntax lets you reference the variable `c` in your extension method(s)
46+
47+
Then in your code you use `circumference` just as though it was originally defined in the `Circle` class:
48+
49+
```scala
50+
aCircle.circumference
51+
```
52+
53+
### Import extension method
54+
55+
Imagine, that `circumference` is defined in package `lib`, you can import it by
56+
57+
```scala
58+
import lib.circumference
59+
60+
aCircle.circumference
61+
```
62+
63+
The compiler also supports you if the import is missing by showing a detailed compilation error message such as the following:
64+
65+
```text
66+
value circumference is not a member of Circle, but could be made available as an extension method.
67+
68+
The following import might fix the problem:
69+
70+
import lib.circumference
71+
```
72+
73+
## Discussion
74+
75+
The `extension` keyword declares that you’re about to define one or more extension methods on the type that’s put in parentheses.
76+
To define multiple extension methods on a type, use this syntax:
77+
78+
```scala
79+
extension (c: Circle)
80+
def circumference: Double = c.radius * math.Pi * 2
81+
def diameter: Double = c.radius * 2
82+
def area: Double = math.Pi * c.radius * c.radius
83+
```
84+
85+
Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
---
2+
title: Given Imports
3+
type: section
4+
description: This page demonstrates how 'given' import statements work in Scala 3.
5+
num: 62
6+
previous-page: ca-context-bounds
7+
next-page: ca-extension-methods
8+
---
9+
10+
11+
To make it more clear where givens in the current scope are coming from, a special form of the `import` statement is used to import `given` instances.
12+
The basic form is shown in this example:
13+
14+
```scala
15+
object A:
16+
class TC
17+
given tc: TC = ???
18+
def f(using TC) = ???
19+
20+
object B:
21+
import A.* // import all non-given members
22+
import A.given // import the given instance
23+
```
24+
25+
In this code the `import A.*` clause of object `B` imports all members of `A` *except* the `given` instance, `tc`.
26+
Conversely, the second import, `import A.given`, imports *only* that `given` instance.
27+
The two `import` clauses can also be merged into one:
28+
29+
```scala
30+
object B:
31+
import A.{given, *}
32+
```
33+
34+
35+
## Discussion
36+
37+
The wildcard selector `*` brings all definitions other than givens or extensions into scope, whereas a `given` selector brings all *givens*---including those resulting from extensions---into scope.
38+
39+
These rules have two main benefits:
40+
41+
- It’s more clear where givens in the current scope are coming from.
42+
In particular, it’s not possible to hide imported givens in a long list of other wildcard imports.
43+
- It enables importing all givens without importing anything else.
44+
This is important because givens can be anonymous, so the usual use of named imports is not practical.
45+
46+
More examples of the “import given” syntax are shown in the [Packaging and Imports chapter][imports].
47+
48+
49+
[imports]: {% link _overviews/scala3-book/packaging-imports.md %}
Lines changed: 97 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,97 @@
1+
---
2+
title: Given Instances and Using Clauses
3+
type: section
4+
description: This page demonstrates how to use 'given' instances and 'using' clauses in Scala 3.
5+
num: 59
6+
previous-page: ca-contextual-abstractions-intro
7+
next-page: types-type-classes
8+
---
9+
10+
Scala 3 offers two important feature for contextual abstraction:
11+
12+
- **Using Clauses** allow you to specify parameters that, at the call site, can be omitted by the programmer and should be automatically provided by the context.
13+
- **Given Instances** let you define terms that can be used by the Scala compiler to fill in the missing arguments.
14+
15+
## Using Clauses
16+
When designing a system, often context information like _configuration_ or settings need to be provided to the different components of your system.
17+
One common way to achieve this is by passing the configuration as additional argument to your methods.
18+
19+
In the following example, we define a case class `Config` to model some website configuration and pass it around in the different methods.
20+
```scala
21+
case class Config(port: Int, baseUrl: String)
22+
23+
def renderWebsite(path: String, c: Config): String =
24+
"<html>" + renderWidget(List("cart"), c) + "</html>"
25+
26+
def renderWidget(items: List[String], c: Config): String = ???
27+
28+
val config = Config(8080, "docs.scala-lang.org")
29+
renderWebsite("/home", config)
30+
```
31+
Let us assume that the configuration does not change throughout most of our code base.
32+
Passing `c` to each and every method call (like `renderWidget`) becomes very tedious and makes our program more difficult to read, since we need to ignore the `c` argument.
33+
34+
#### Using `using` to mark parameters as contextual
35+
In Scala 3, we can mark some of the parameters of our methods as _contextual_.
36+
```scala
37+
def renderWebsite(path: String)(using c: Config): String =
38+
"<html>" + renderWidget(List("cart")) + "</html>"
39+
// ^^^
40+
// no argument c required anymore
41+
42+
def renderWidget(items: List[String])(using c: Config): String = ???
43+
```
44+
By starting a parameter section with the keyword `using`, we tell the Scala compiler that at the callsite it should automatically find an argument with the correct type.
45+
The Scala compiler thus performs **term inference**.
46+
47+
In our call to `renderWidget(List("cart"))` the Scala compiler will see that there is a term of type `Config` in scope (the `c`) and automatically provide it to `renderWidget`.
48+
So the program is equivalent to the one above.
49+
50+
In fact, since we do not need to refer to `c` in our implementation of `renderWebsite` anymore, we can even omit its name in the signature:
51+
52+
```scala
53+
// no need to come up with a parameter name
54+
// vvvvvvvvvvvvv
55+
def renderWebsite(path: String)(using Config): String =
56+
"<html>" + renderWidget(List("cart")) + "</html>"
57+
```
58+
59+
#### Explicitly providing contextual arguments
60+
We have seen how to _abstract_ over contextual parameters and that the Scala compiler can provide arguments automatically for us.
61+
But how can we specify which configuration to use for our call to `renderWebsite`?
62+
63+
Like we specified our parameter section with `using`, we can also explicitly provide contextual arguments with `using:`
64+
65+
```scala
66+
renderWebsite("/home")(using config)
67+
```
68+
Explicitly providing contextual parameters can be useful if we have multiple different values in scope that would make sense and we want to make sure that the correct one is passed to the function.
69+
70+
For all other cases, as we will see in the next Section, there is also another way to bring contextual values into scope.
71+
72+
## Given Instances
73+
We have seen that we can explicitly pass arguments as contextual parameters by marking the argument section of the _call_ with `using`.
74+
However, if there is _a single canonical value_ for a particular type, there is another preferred way to make it available to the Scala compiler: by marking it as `given`.
75+
76+
```scala
77+
val config = Config(8080, "docs.scala-lang.org")
78+
// this is the type that we want to provide the
79+
// canonical value for
80+
// vvvvvv
81+
given Config = config
82+
// ^^^^^^
83+
// this is the value the Scala compiler will infer
84+
// as argument to contextual parameters of type Config
85+
```
86+
In the above example we specify that whenever a contextual parameter of type `Config` is omitted in the current scope, the compiler should infer `config` as an argument.
87+
88+
Having defined a given for `Config`, we can simply call `renderWebsite`:
89+
90+
```scala
91+
renderWebsite("/home")
92+
// ^^^^^
93+
// again no argument
94+
```
95+
96+
[reference]: {{ site.scala3ref }}/overview.html
97+
[blog-post]: /2020/11/06/explicit-term-inference-in-scala-3.html

0 commit comments

Comments
 (0)