Skip to content

Commit 5f73987

Browse files
Merge pull request #9417 from ShapelessCat/fix-docs-optional-braces
Fix typos and alignment in indentation.md
2 parents fabe7bb + 9061cd5 commit 5f73987

File tree

1 file changed

+83
-68
lines changed

1 file changed

+83
-68
lines changed

docs/docs/reference/other-new-features/indentation.md

Lines changed: 83 additions & 68 deletions
Original file line numberDiff line numberDiff line change
@@ -7,9 +7,9 @@ As an experimental feature, Scala 3 enforces some rules on indentation and allow
77
some occurrences of braces `{...}` to be optional.
88
It can be turned off with the compiler flag `-noindent`.
99

10-
- First, some badly indented programs are flagged with warnings.
11-
- Second, some occurrences of braces `{...}` are made optional. Generally, the rule
12-
is that adding a pair of optional braces will not change the meaning of a well-indented program.
10+
- First, some badly indented programs are flagged with warnings.
11+
- Second, some occurrences of braces `{...}` are made optional. Generally, the rule
12+
is that adding a pair of optional braces will not change the meaning of a well-indented program.
1313

1414
### Indentation Rules
1515

@@ -62,9 +62,11 @@ There are two rules:
6262
- after the leading parameters of an `extension`, or
6363
- after a ": at end of line" token (see below)
6464
- after one of the following tokens:
65+
6566
```
6667
= => <- if then else while do try catch finally for yield match return
6768
```
69+
6870
If an `<indent>` is inserted, the indentation width of the token on the next line
6971
is pushed onto `IW`, which makes it the new current indentation width.
7072

@@ -75,7 +77,7 @@ There are two rules:
7577
- the first token on the next line is not a
7678
[leading infix operator](../changed-features/operators.html).
7779

78-
If an `<outdent>` is inserted, the top element if popped from `IW`.
80+
If an `<outdent>` is inserted, the top element is popped from `IW`.
7981
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
8082
may be inserted in a row.
8183

@@ -84,12 +86,14 @@ There are two rules:
8486
An `<outdent>` is finally inserted in front of a comma that follows a statement sequence starting with an `<indent>` if the indented region is itself enclosed in parentheses
8587

8688
It is an error if the indentation width of the token following an `<outdent>` does not match the indentation of some previous line in the enclosing indentation region. For instance, the following would be rejected.
89+
8790
```scala
8891
if x < 0
8992
-x
9093
else // error: `else` does not align correctly
9194
x
9295
```
96+
9397
Indentation tokens are only inserted in regions where newline statement separators are also inferred:
9498
at the toplevel, inside braces `{...}`, but not inside parentheses `(...)`, patterns or types.
9599

@@ -105,6 +109,7 @@ that can start an indentation region. The Scala grammar is changed so an optiona
105109
Analogous rules apply for enum bodies, type refinements, definitions in an instance creation expressions, and local packages containing nested definitions.
106110

107111
With these new rules, the following constructs are all valid:
112+
108113
```scala
109114
trait A:
110115
def f: Int
@@ -137,12 +142,14 @@ package q:
137142
```
138143

139144
The syntax changes allowing this are as follows:
145+
140146
```
141147
TemplateBody ::= [colonEol] ‘{’ [SelfType] TemplateStat {semi TemplateStat} ‘}’
142148
EnumBody ::= [colonEol] ‘{’ [SelfType] EnumStat {semi EnumStat} ‘}’
143149
Packaging ::= ‘package’ QualId [colonEol] ‘{’ TopStatSeq ‘}’
144150
RefinedType ::= AnnotType {[colonEol] Refinement}
145151
```
152+
146153
Here, `colonEol` stands for ": at end of line", as described above.
147154
The lexical analyzer is modified so that a `:` at the end of a line
148155
is reported as `colonEol` if the parser is at a point where a `colonEol` is
@@ -166,13 +173,14 @@ Indentation can be mixed freely with braces. For interpreting indentation inside
166173

167174
The indentation rules for `match` expressions and `catch` clauses are refined as follows:
168175

169-
- An indentation region is opened after a `match` or `catch` also if the following `case`
170-
appears at the indentation width that's current for the `match` itself.
171-
- In that case, the indentation region closes at the first token at that
172-
same indentation width that is not a `case`, or at any token with a smaller
173-
indentation width, whichever comes first.
176+
- An indentation region is opened after a `match` or `catch` also if the following `case`
177+
appears at the indentation width that's current for the `match` itself.
178+
- In that case, the indentation region closes at the first token at that
179+
same indentation width that is not a `case`, or at any token with a smaller
180+
indentation width, whichever comes first.
174181

175182
The rules allow to write `match` expressions where cases are not indented themselves, as in the example below:
183+
176184
```scala
177185
x match
178186
case 1 => print("I")
@@ -189,6 +197,7 @@ println(".")
189197
Indentation-based syntax has many advantages over other conventions. But one possible problem is that it makes it hard to discern when a large indentation region ends, since there is no specific token that delineates the end. Braces are not much better since a brace by itself also contains no information about what region is closed.
190198

191199
To solve this problem, Scala 3 offers an optional `end` marker. Example:
200+
192201
```scala
193202
def largeMethod(...) =
194203
...
@@ -199,80 +208,84 @@ def largeMethod(...) =
199208
... // more code
200209
end largeMethod
201210
```
211+
202212
An `end` marker consists of the identifier `end` and a follow-on specifier token that together constitute all the tokes of a line. Possible specifier tokens are
203213
identifiers or one of the following keywords
214+
204215
```scala
205216
if while for match try new this val given
206217
```
218+
207219
End markers are allowed in statement sequences. The specifier token `s` of an end marker must correspond to the statement that precedes it. This means:
208220

209-
- If the statement defines a member `x` then `s` must be the same identifier `x`.
210-
- If the statement defines a constructor then `s` must be `this`.
211-
- If the statement defines an anonymous given, then `s` must be `given`.
212-
- If the statement defines an anonymous extension, then `s` must be `extension`.
213-
- If the statement defines an anonymous class, then `s` must be `new`.
214-
- If the statement is a `val` definition binding a pattern, then `s` must be `val`.
215-
- If the statement is a package clause that refers to package `p`, then `s` must be the same identifier `p`.
216-
- If the statement is an `if`, `while`, `for`, `try`, or `match` statement, then `s` must be that same token.
221+
- If the statement defines a member `x` then `s` must be the same identifier `x`.
222+
- If the statement defines a constructor then `s` must be `this`.
223+
- If the statement defines an anonymous given, then `s` must be `given`.
224+
- If the statement defines an anonymous extension, then `s` must be `extension`.
225+
- If the statement defines an anonymous class, then `s` must be `new`.
226+
- If the statement is a `val` definition binding a pattern, then `s` must be `val`.
227+
- If the statement is a package clause that refers to package `p`, then `s` must be the same identifier `p`.
228+
- If the statement is an `if`, `while`, `for`, `try`, or `match` statement, then `s` must be that same token.
217229

218230
For instance, the following end markers are all legal:
219-
```scala
220-
package p1.p2:
221-
222-
abstract class C():
223-
224-
def this(x: Int) =
225-
this()
226-
if x > 0 then
227-
val a :: b =
228-
x :: Nil
229-
end val
230-
var y =
231-
x
232-
end y
233-
while y > 0 do
234-
println(y)
235-
y -= 1
236-
end while
237-
try
238-
x match
239-
case 0 => println("0")
240-
case _ =>
241-
end match
242-
finally
243-
println("done")
244-
end try
245-
end if
246-
end this
247-
248-
def f: String
249-
end C
250-
251-
object C:
252-
given C =
253-
new C:
254-
def f = "!"
255-
end f
256-
end new
257-
end given
258-
end C
259-
260-
extension (x: C)
261-
def ff: String = x.f ++ x.f
262-
end extension
263-
264-
end p2
231+
232+
```scala
233+
package p1.p2:
234+
235+
abstract class C():
236+
237+
def this(x: Int) =
238+
this()
239+
if x > 0 then
240+
val a :: b =
241+
x :: Nil
242+
end val
243+
var y =
244+
x
245+
end y
246+
while y > 0 do
247+
println(y)
248+
y -= 1
249+
end while
250+
try
251+
x match
252+
case 0 => println("0")
253+
case _ =>
254+
end match
255+
finally
256+
println("done")
257+
end try
258+
end if
259+
end this
260+
261+
def f: String
262+
end C
263+
264+
object C:
265+
given C =
266+
new C:
267+
def f = "!"
268+
end f
269+
end new
270+
end given
271+
end C
272+
273+
extension (x: C)
274+
def ff: String = x.f ++ x.f
275+
end extension
276+
277+
end p2
265278
```
266279

267280
#### When to Use End Markers
268281

269282
It is recommended that `end` markers are used for code where the extent of an indentation region is not immediately apparent "at a glance". People will have different preferences what this means, but one can nevertheless give some guidelines that stem from experience. An end marker makes sense if
270283

271-
- the construct contains blank lines, or
272-
- the construct is long, say 15-20 lines or more,
273-
- the construct ends heavily indented, say 4 indentation levels or more.
284+
- the construct contains blank lines, or
285+
- the construct is long, say 15-20 lines or more,
286+
- the construct ends heavily indented, say 4 indentation levels or more.
274287

275-
If none of these criteria apply, it's often better to not use an end marker since the code will be just as clear and more concise. If there are several ending regions that satisfy one of the criteria above, we usually need an end marker only for the outermost closed reason. So cascades of end markers as in the example above are usually better avoided.
288+
If none of these criteria apply, it's often better to not use an end marker since the code will be just as clear and more concise. If there are several ending regions that satisfy one of the criteria above, we usually need an end marker only for the outermost closed region. So cascades of end markers as in the example above are usually better avoided.
276289

277290
#### Syntax
278291

@@ -359,14 +372,16 @@ times(10):
359372
println("ah")
360373
println("ha")
361374
```
375+
362376
or
377+
363378
```scala
364379
xs.map:
365380
x =>
366381
val y = x - 1
367382
y * y
368383
```
384+
369385
Colons at the end of lines are their own token, distinct from normal `:`.
370386
The Scala grammar is changed in this variant so that colons at end of lines are accepted at all points
371387
where an opening brace enclosing a function argument is legal. 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.
372-

0 commit comments

Comments
 (0)