You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Copy file name to clipboardExpand all lines: docs/docs/reference/other-new-features/indentation.md
+79-72
Original file line number
Diff line number
Diff line change
@@ -3,9 +3,7 @@ layout: doc-page
3
3
title: Significant Indentation
4
4
---
5
5
6
-
As an experimental feature, Scala 3 treats indentation as significant.
7
-
8
-
Indentation is significant everywhere except inside regions delineated by braces `{...}`, brackets `[...]` or parentheses `(...)` or within string or character literals.
6
+
As an experimental feature, Scala 3 treats indentation as significant. Indentation is significant everywhere except inside regions delineated by brackets `[...]` or parentheses `(...)`.
9
7
10
8
Where indentation is significant, the compiler will insert `<indent>` or `<outdent>`
11
9
tokens at certain line breaks. Grammatically, pairs of `<indent>` and `<outdent>` tokens have the same effect as pairs of braces `{` and `}`.
@@ -17,38 +15,50 @@ There are two rules:
17
15
1. An `<indent>` is inserted at a line break, if
18
16
19
17
- the first token on the next line has an indentation width strictly greater
20
-
than the current indentation width, and
18
+
than the current indentation width, and
21
19
- the last token on the previous line can start an indentation region.
22
20
23
-
The following tokens can start an indentation region:
21
+
The following tokens can start an indentation region:
24
22
```
25
-
: = => <- if then else while do try catch finally for yield match
23
+
: = => <- if then else while do try catch finally for yield match
26
24
```
27
25
28
-
If an `<indent>` is inserted, the indentation width of the token on the next line
29
-
is pushed onto `IW`, which makes it the new current indentation width.
26
+
If an `<indent>` is inserted, the indentation width of the token on the next line
27
+
is pushed onto `IW`, which makes it the new current indentation width.
30
28
31
29
2. An `<outdent>` is inserted at a line break, if
32
30
33
31
- the first token on the next line has an indentation width strictly less
If an `<outdent>` is inserted, the top element if popped from `IW`.
39
-
If the indentation width of the token on the next line is still less than the new current indentation width, step (2) repeats. Therefore, several `<outdent>` tokens
40
-
may be inserted in a row.
36
+
If an `<outdent>` is inserted, the top element if popped from `IW`.
37
+
If the indentation width of the token on the next line is still less than the new current indentation width, step (2) repeats. Therefore, several `<outdent>` tokens
38
+
may be inserted in a row.
41
39
42
40
It is an error if the indentation width of the token following an `<outdent>` does not
43
41
match the indentation of some previous line in the enclosing indentation region. For instance, the following would be rejected.
44
42
```scala
45
43
if x < 0 then
46
44
-x
47
45
else // error: `else` does not align correctly
48
-
x
46
+
x
49
47
```
50
48
51
-
Indentation prefixes can consist of spaces and tabs. Indentation widths are the indentation prefixes themselves, ordered by the string prefix relation. So, so for instance "2 tabs, followed by 4 spaces" is strictly less than "2 tabs, followed by 5 spaces", but "2 tabs, followed by 4 spaces" is incomparable to "6 tabs" or to "4 spaces, followed by 2 tabs". It is an error if the indentation width of some line is incomparable with the indentation width of the region that's current at that point. To avoid such errors, it is a good idea not to mix spaces and tabs in the same source file.
49
+
### Spaces vs Tabs
50
+
51
+
Indentation prefixes can consist of spaces and/or tabs. Indentation widths are the indentation prefixes themselves, ordered by the string prefix relation. So, so for instance "2 tabs, followed by 4 spaces" is strictly less than "2 tabs, followed by 5 spaces", but "2 tabs, followed by 4 spaces" is incomparable to "6 tabs" or to "4 spaces, followed by 2 tabs". It is an error if the indentation width of some line is incomparable with the indentation width of the region that's current at that point. To avoid such errors, it is a good idea not to mix spaces and tabs in the same source file.
52
+
53
+
### Indentation and Braces
54
+
55
+
Indentatation can be mixed freely with braces. For interpreting indentation inside braces, the following rules apply.
56
+
57
+
1. The assumed indentation width of a multiline region enclosed in braces is the
58
+
indentation width of the first token that starts a new line after the opening brace.
59
+
60
+
2. On encountering a closing brace `}`, as many `<outdent>` tokens as necessary are
61
+
inserted to close all open indentation regions inside the pair of braces.
52
62
53
63
### Indentation Marker `:`
54
64
@@ -63,14 +73,13 @@ or
63
73
```scala
64
74
xs.map:
65
75
x =>
66
-
valy= x -1
67
-
y * y
76
+
valy= x -1
77
+
y * y
68
78
```
69
79
Colons at the end of lines are their own token, distinct from normal `:`.
70
80
The Scala grammar is changed so that colons at end of lines are accepted at all points
71
81
where an opening brace is legal, except if the previous token can already start an
72
-
indentation region. Special provisions are taken so that method result types can still use a colon on
73
-
the end of a line, followed by the actual type on the next.
82
+
indentation region. Special provisions are taken so that method result types can still use a colon on the end of a line, followed by the actual type on the next.
74
83
75
84
### Special Treatment of Case Clauses
76
85
@@ -80,7 +89,7 @@ The indentation rules for `match` expressions and `catch` clauses are refined as
80
89
appears at the indentation width that's current for the `match` itself.
81
90
- In that case, the indentation region closes at the first token at that
82
91
same indentation width that is not a `case`, or at any token with a smaller
83
-
indentation width, whichever comes first.
92
+
indentation width, whichever comes first.
84
93
85
94
The rules allow to write `match` expressions where cases are not indented themselves, as in the example below:
86
95
```scala
@@ -113,8 +122,8 @@ An `end` marker consists of the identifier `end` which follows an `<outdent>` to
113
122
```scala
114
123
ifwhileformatchtrynew
115
124
```
116
-
If `end` is followed by a reserved word, the compiler checks that the marker closes an indentation region belonging to a construct that starts with the reserved word. If it is followed by an identifier _id_, the compiler checks that the marker closes an indentation region containing the right hand side of a `val`, `var`, or `def` or
117
-
the body of a class, trait, object, enum, given instance, or package clause that defines_id_.
125
+
If `end` is followed by a reserved word, the compiler checks that the marker closes an indentation region belonging to a construct that starts with the reserved word. If it is followed by an identifier _id_, the compiler checks that the marker closes a definition
126
+
that defines _id_or a package clause that refers to_id_.
118
127
119
128
`end` itself is a soft keyword. It is only treated as an `end` marker if it
120
129
occurs at the start of a line and is followed by an identifier or one of the reserved words above.
@@ -127,59 +136,57 @@ Here is a (somewhat meta-circular) example of code using indentation. It provide
def< (that: IndentWidth):Boolean=this<= that &&!(that <=this)
154
+
155
+
overridedeftoString:String=
156
+
thismatch
157
+
caseRun(ch, n) =>
158
+
valkind= ch match
159
+
case' '=>"space"
160
+
case'\t'=>"tab"
161
+
case _ =>s"'$ch'-character"
162
+
valsuffix=if n ==1then""else"s"
163
+
s"$n$kind$suffix"
164
+
caseConc(l, r) =>
165
+
s"$l, $r"
161
166
162
167
objectIndentWidth:
163
-
privateinlinevalMaxCached=40
164
-
165
-
privatevalspaces=IArray.tabulate(MaxCached+1):
166
-
newRun(' ', _)
167
-
privatevaltabs=IArray.tabulate(MaxCached+1):
168
-
newRun('\t', _)
169
-
170
-
defRun(ch: Char, n: Int):Run=
171
-
if n <=MaxCached&& ch ==' 'then
172
-
spaces(n)
173
-
elseif n <=MaxCached&& ch =='\t'then
174
-
tabs(n)
175
-
else
176
-
newRun(ch, n)
177
-
178
-
valZero=Run(' ', 0)
179
-
endIndentWidth
168
+
privateinlinevalMaxCached=40
169
+
170
+
privatevalspaces=IArray.tabulate(MaxCached+1):
171
+
newRun(' ', _)
172
+
privatevaltabs=IArray.tabulate(MaxCached+1):
173
+
newRun('\t', _)
174
+
175
+
defRun(ch: Char, n: Int):Run=
176
+
if n <=MaxCached&& ch ==' 'then
177
+
spaces(n)
178
+
elseif n <=MaxCached&& ch =='\t'then
179
+
tabs(n)
180
+
else
181
+
newRun(ch, n)
182
+
endRun
183
+
184
+
valZero=Run(' ', 0)
180
185
```
181
186
182
-
### Rewrites
187
+
### Settings and Rewrites
188
+
189
+
Significant indentation is enabled by default. It can be turned off by giving any of the options `-noindent`, `old-syntax` and `language:Scala2`. If indentation is turned off, it is nevertheless checked that indentation conforms to the logical program structure as defined by braces. If that is not the case, the compiler issues an error (or, in the case of `-language:Scala2`, a migration warning).
183
190
184
191
The Dotty compiler can rewrite source code to indented code and back.
185
192
When invoked with options `-rewrite -indent` it will rewrite braces to
0 commit comments