Skip to content

Commit 0cb1c34

Browse files
authored
Add more guidelines for labelling code examples for Scala 2/3 (#2768)
* Clarify how to label entire pages of documentation that are specific to a Scala version * Add a note that all the code examples assume a specific version of Scala in the “version-specific-notice” * Use the new way of labelling pages in Multiversal Equality * Use the new way of labelling pages in Given Instances and Using Clauses, and adjust the “version-specific-notice”. * Label “types-union” * Also label the chinese version of types-union.md * Label the page types-adts-gadts.md as “New in Scala 3”
1 parent 86fe255 commit 0cb1c34

File tree

7 files changed

+75
-51
lines changed

7 files changed

+75
-51
lines changed

_includes/version-specific-notice.html

+6-2
Original file line numberDiff line numberDiff line change
@@ -3,10 +3,14 @@
33
<i class="fa fa-info"></i><span style="margin-left: 0.5rem">
44
{% if include.language == 'scala3' %}
55
This doc page is specific to Scala 3,
6-
and may cover new concepts not available in Scala 2.
6+
and may cover new concepts not available in Scala 2. Unless
7+
otherwise stated, all the code examples in this page assume
8+
you are using Scala 3.
79
{% else if include.language == 'scala2' %}
810
This doc page is specific to features shipped in Scala 2,
9-
which have either been removed in Scala 3 or replaced by an alternative.
11+
which have either been removed in Scala 3 or replaced by an
12+
alternative. Unless otherwise stated, all the code examples
13+
in this page assume you are using Scala 2.
1014
{% endif %}
1115
</span>
1216
</blockquote>

_overviews/contribute/add-guides.md

+53-4
Original file line numberDiff line numberDiff line change
@@ -83,7 +83,7 @@ clarifications, etc.
8383
## Code blocks
8484

8585
It's common for various kinds of documents to require code examples.
86-
You can contribute code in a markdown document by either
86+
You can contribute code in a Markdown document by either
8787
- in-line by putting backticks around it,
8888
- surrounding by triple backticks,
8989
- or indenting it by 4 spaces, e.g.:
@@ -92,6 +92,7 @@ You can contribute code in a markdown document by either
9292
inline example: `val x = 23`
9393
9494
block example:
95+
9596
```scala
9697
println("hello")
9798
```
@@ -103,9 +104,31 @@ indented example:
103104

104105
### Scala 2 vs Scala 3
105106

106-
Sometimes you would like to compare between Scala 2 and Scala 3 in a document, for example in
107-
our [Hello World][hello-world] chapter of the Scala Book. Here is an example of how you
108-
can generate the same tabs in markdown with the `tabs` directive and class `tabs-scala-version`:
107+
Our goal is to have a unified documentation that covers both Scala 2 and Scala 3. In many cases, the
108+
code examples are the same in both Scala 2 and Scala 3, but sometimes there are some syntactic
109+
differences. In some less common cases, a page may explain a concept that is new in Scala 3 and has
110+
no equivalent in Scala 2, or a concept that has been removed in Scala 3. In all the cases, the
111+
documentation should clearly "label" the code examples so that the readers know in which versions
112+
of Scala they are valid.
113+
114+
The following sections explain how to properly "label" the code examples.
115+
116+
#### Labelling the code snippets of a page documenting a concept available in both Scala 2 and Scala 3
117+
118+
When the content of a page not specific to Scala 2 or Scala 3, like for example our
119+
[Hello World][hello-world] chapter of the Scala Book, the code snippets should show both the
120+
Scala 2 and Scala 3 syntax. We achieve this by labelling the code snippets in tabs according
121+
to the following rules:
122+
123+
- if the idiomatic syntax is different in Scala 2 and Scala 3, we create two tabs,
124+
“Scala 2” and “Scala 3”, showing the corresponding syntax
125+
- if the code snippet is idiomatic in both Scala 2 and Scala 3, we create a single tab,
126+
“Scala 2 and 3”
127+
- if the code snippet is valid only in Scala 2 or Scala 3, we create a single tab,
128+
“Scala 2 Only” or “Scala 3 Only”
129+
130+
Here is an example of how you
131+
can generate such tabs in Markdown with the `tabs` directive and class `tabs-scala-version`:
109132

110133
<!-- {% raw %} -->
111134
~~~liquid
@@ -161,6 +184,32 @@ a parameter `for=tab-group` as in this example:
161184
~~~
162185
<!-- {% endraw %} -->
163186

187+
#### Labelling an entire page documenting a concept that is specific to a Scala version
188+
189+
When the content of a page explains a concept that is new in Scala 3 and has no
190+
equivalent in Scala 2 (e.g. [TASTy]({% link scala3/guides/tasty-overview.md %})),
191+
or a concept that has been removed in Scala 3, we label the entire page instead
192+
of labelling each code example.
193+
194+
We achieve this by setting a couple of a attributes in the [YAML front
195+
matter](https://jekyllrb.com/docs/front-matter/) of the Markdown file. For
196+
instance, for a page that is specific to Scala 3:
197+
198+
~~~ yaml
199+
scala3: true
200+
versionSpecific: true
201+
~~~
202+
203+
Or, for a page that is specific to Scala 2:
204+
205+
~~~ yaml
206+
scala2: true
207+
versionSpecific: true
208+
~~~
209+
210+
Please note that when the entire page is labelled, its code examples do not
211+
need to have tabs.
212+
164213
### Typechecked Examples
165214

166215
The site build process uses [mdoc](https://scalameta.org/mdoc/) to typecheck

_overviews/scala3-book/ca-given-using-clauses.md

+2-39
Original file line numberDiff line numberDiff line change
@@ -6,11 +6,10 @@ languages: [zh-cn]
66
num: 60
77
previous-page: ca-extension-methods
88
next-page: ca-context-bounds
9+
scala3: true
10+
versionSpecific: true
911
---
1012

11-
12-
<h5>Use contextual abstraction <span class="tag tag-inline">Scala 3 Only</span></h5>
13-
1413
Scala 3 offers two important feature for contextual abstraction:
1514

1615
- **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.
@@ -23,9 +22,6 @@ One common way to achieve this is by passing the configuration as additional arg
2322

2423
In the following example, we define a case class `Config` to model some website configuration and pass it around in the different methods.
2524

26-
{% tabs nonusing %}
27-
{% tab 'Scala 2 and 3' %}
28-
2925
```scala
3026
case class Config(port: Int, baseUrl: String)
3127

@@ -38,19 +34,13 @@ val config = Config(8080, "docs.scala-lang.org")
3834
renderWebsite("/home", config)
3935
```
4036

41-
{% endtab %}
42-
{% endtabs %}
43-
4437
Let us assume that the configuration does not change throughout most of our code base.
4538
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.
4639

4740
#### Using `using` to mark parameters as contextual
4841

4942
In Scala 3, we can mark some parameters of our methods as _contextual_.
5043

51-
{% tabs using1 %}
52-
{% tab 'Scala 3 Only' %}
53-
5444
```scala
5545
def renderWebsite(path: String)(using c: Config): String =
5646
"<html>" + renderWidget(List("cart")) + "</html>"
@@ -60,9 +50,6 @@ def renderWebsite(path: String)(using c: Config): String =
6050
def renderWidget(items: List[String])(using c: Config): String = ???
6151
```
6252

63-
{% endtab %}
64-
{% endtabs %}
65-
6653
By starting a parameter section with the keyword `using`, we tell the Scala compiler that at the call-site it should automatically find an argument with the correct type.
6754
The Scala compiler thus performs **term inference**.
6855

@@ -71,36 +58,24 @@ So the program is equivalent to the one above.
7158

7259
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:
7360

74-
{% tabs using2 %}
75-
{% tab 'Scala 3 Only' %}
76-
7761
```scala
7862
// no need to come up with a parameter name
7963
// vvvvvvvvvvvvv
8064
def renderWebsite(path: String)(using Config): String =
8165
"<html>" + renderWidget(List("cart")) + "</html>"
8266
```
8367

84-
{% endtab %}
85-
{% endtabs %}
86-
8768
#### Explicitly providing contextual arguments
8869

8970
We have seen how to _abstract_ over contextual parameters and that the Scala compiler can provide arguments automatically for us.
9071
But how can we specify which configuration to use for our call to `renderWebsite`?
9172

9273
Like we specified our parameter section with `using`, we can also explicitly provide contextual arguments with `using:`
9374

94-
{% tabs using3 %}
95-
{% tab 'Scala 3 Only' %}
96-
9775
```scala
9876
renderWebsite("/home")(using config)
9977
```
10078

101-
{% endtab %}
102-
{% endtabs %}
103-
10479
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.
10580

10681
For all other cases, as we will see in the next Section, there is also another way to bring contextual values into scope.
@@ -110,9 +85,6 @@ For all other cases, as we will see in the next Section, there is also another w
11085
We have seen that we can explicitly pass arguments as contextual parameters by marking the argument section of the _call_ with `using`.
11186
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`.
11287

113-
{% tabs given1 %}
114-
{% tab 'Scala 3 Only' %}
115-
11688
```scala
11789
val config = Config(8080, "docs.scala-lang.org")
11890
// this is the type that we want to provide the
@@ -124,24 +96,15 @@ given Config = config
12496
// as argument to contextual parameters of type Config
12597
```
12698

127-
{% endtab %}
128-
{% endtabs %}
129-
13099
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.
131100

132101
Having defined a given for `Config`, we can simply call `renderWebsite`:
133102

134-
{% tabs given2 %}
135-
{% tab 'Scala 3 Only' %}
136-
137103
```scala
138104
renderWebsite("/home")
139105
// ^^^^^
140106
// again no argument
141107
```
142108

143-
{% endtab %}
144-
{% endtabs %}
145-
146109
[reference]: {{ site.scala3ref }}/overview.html
147110
[blog-post]: /2020/11/06/explicit-term-inference-in-scala-3.html

_overviews/scala3-book/ca-multiversal-equality.md

+2-5
Original file line numberDiff line numberDiff line change
@@ -6,12 +6,9 @@ languages: [zh-cn]
66
num: 64
77
previous-page: ca-type-classes
88
next-page: ca-implicit-conversions
9+
scala3: true
10+
versionSpecific: true
911
---
10-
<span class="tag tag-inline">New In Scala 3</span>
11-
12-
> Multiversal Equality is a new language feature that was introduced in Scala 3.
13-
> Because it has no equivalent in Scala 2, all code examples
14-
> in this lesson assume you are using Scala 3.
1512

1613
Previously, Scala had *universal equality*: Two values of any types could be compared with each other using `==` and `!=`.
1714
This came from the fact that `==` and `!=` are implemented in terms of Java’s `equals` method, which can also compare values of any two reference types.

_overviews/scala3-book/types-adts-gadts.md

+2
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,8 @@ languages: [zh-cn]
66
num: 52
77
previous-page: types-union
88
next-page: types-variance
9+
scala3: true
10+
versionSpecific: true
911
---
1012

1113

_overviews/scala3-book/types-union.md

+4-1
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,8 @@ languages: [zh-cn]
66
num: 51
77
previous-page: types-intersection
88
next-page: types-adts-gadts
9+
scala3: true
10+
versionSpecific: true
911
---
1012

1113
Used on types, the `|` operator creates a so-called _union type_.
@@ -43,14 +45,15 @@ case 1.0 => ??? // ERROR: this line won’t compile
4345
As shown, union types can be used to represent alternatives of several different types, without requiring those types to be part of a custom-crafted class hierarchy, or requiring explicit wrapping.
4446

4547
#### Pre-planning the Class Hierarchy
46-
Other languages would require pre-planning of the class hierarchy, like the following example illustrates:
48+
Without union types, it would require pre-planning of the class hierarchy, like the following example illustrates:
4749

4850
```scala
4951
trait UsernameOrPassword
5052
case class Username(name: String) extends UsernameOrPassword
5153
case class Password(hash: Hash) extends UsernameOrPassword
5254
def help(id: UsernameOrPassword) = ...
5355
```
56+
5457
Pre-planning does not scale very well since, for example, requirements of API users might not be foreseeable.
5558
Additionally, cluttering the type hierarchy with marker traits like `UsernameOrPassword` also makes the code more difficult to read.
5659

_zh-cn/overviews/scala3-book/types-union.md

+6
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,8 @@ partof: scala3-book
1111
overview-name: "Scala 3 — Book"
1212
layout: multipage-overview
1313
permalink: "/zh-cn/scala3/book/:title.html"
14+
scala3: true
15+
versionSpecific: true
1416
---
1517

1618

@@ -54,12 +56,16 @@ case 1.0 => ??? // ERROR: this line won’t compile
5456

5557
其他语言需要预先规划类层次结构,如下例所示:
5658

59+
{% tabs pre-planning %}
60+
{% tab 'Scala 2 and 3' %}
5761
```scala
5862
trait UsernameOrPassword
5963
case class Username(name: String) extends UsernameOrPassword
6064
case class Password(hash: Hash) extends UsernameOrPassword
6165
def help(id: UsernameOrPassword) = ...
6266
```
67+
{% endtab %}
68+
{% endtabs %}
6369

6470
预先计划不能很好地扩展,例如,API 用户的需求可能无法预见。
6571
此外,使用诸如 `UsernameOrPassword` 之类的标记 trait 使类型层次结构混乱也会使代码更难阅读。

0 commit comments

Comments
 (0)