Skip to content

Commit 4181d9f

Browse files
authored
Merge pull request #625 from dwijnand/traily
SIP-27: Trailing Commas, revised document
2 parents 07e420a + afd7091 commit 4181d9f

File tree

1 file changed

+131
-52
lines changed

1 file changed

+131
-52
lines changed

sips/completed/_posts/2016-06-25-trailing-commas.md

Lines changed: 131 additions & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -3,31 +3,33 @@ layout: sip
33
disqus: true
44
title: SIP-27 - Trailing Commas
55

6-
vote-status: accepted
6+
vote-status: under review
77
vote-text: The following proposal needs to be updated, since only the specialized case version (with new lines) has been accepted. For more information, check the <a href="http://docs.scala-lang.org/sips/minutes/sip-20th-september-minutes.html">minutes</a>.
88
---
99

10+
// TODO: Move from sips/completed to sips/pending
11+
1012
**By: Dale Wijnand**
1113

1214
## History
1315

14-
| Date | Version |
15-
| ---------------|-------------------------------------------------|
16-
| Jun 25th 2016 | Initial Draft |
17-
| Jun 27th 2016 | Added drawback of changing existing tools |
18-
| Jun 27th 2016 | Added motivation that it simplifies codegen |
19-
| Jun 28th 2016 | Fixed a typo |
20-
| Aug 10th 2016 | Renamed from SIP-NN to SIP-27 |
21-
| Aug 10th 2016 | Changed scala-commas URL (repo was moved) |
22-
| Aug 10th 2016 | Dialed back some of the language from review |
23-
| Sep 04th 2016 | Split the motivation into sections |
24-
| Sep 04th 2016 | Add VCS authorship attribution to motivation |
25-
| Sep 04th 2016 | Add Cross building hinderance to drawbacks |
26-
| Sep 12th 2016 | Remove Cross building hinderance from drawbacks |
16+
| Date | Version |
17+
| ---------------|------------------------------------------------------------|
18+
| Jun 25th 2016 | Initial Draft ([#533][]) |
19+
| Jun 27th 2016 | New drawback: changing existing tools ([#533][]) |
20+
| Jun 27th 2016 | New motivation: simplifies codegen ([#533][]) |
21+
| Aug 10th 2016 | SIP numbered: Renamed to SIP-27 ([#533][]) |
22+
| Aug 10th 2016 | Changed scala-commas URL (repo was moved) ([#533][]) |
23+
| Aug 10th 2016 | Dialed back some of the language ([#533][]) |
24+
| Sep 04th 2016 | Split the motivation into sections ([#533][]) |
25+
| Sep 04th 2016 | New motivation: VCS authorship attribution ([#533][]) |
26+
| Sep 04th 2016 | New drawback: Cross building hinderance ([#533][]) |
27+
| Sep 12th 2016 | Remove cross building hinderance from drawbacks ([#533][]) |
28+
| Nov 12th 2016 | Major rework: multi-line, 2 variants & spec ([#625][]) |
2729

2830
## Motivation
2931

30-
### Easy to modify lists
32+
### Ease of modification
3133

3234
When using a comma-separated sequence of elements on multiple lines, such as:
3335

@@ -39,33 +41,33 @@ Seq(
3941
)
4042
{% endhighlight %}
4143

42-
It is quite inconvenient to remove or comment out any element because one has to think about the fact that the last element mustn't have a trailing comma:
44+
It is inconvenient to remove or comment out elements because the last element mustn't have a trailing comma:
4345

4446
{% highlight scala %}
45-
Map(
47+
Seq(
4648
foo,
47-
bar //,
49+
bar,
4850
// baz
49-
)
51+
) // error: illegal start of simple expression
5052
{% endhighlight %}
5153

52-
Secondly, it is quite inconvenient to re-order the sequence, for instance if you wanted `baz` before `bar` you need to micromanage which is followed by a comma and which isn't:
54+
It is also inconvenient to reorder because every element but the last one must be followed by a comma:
5355

5456
{% highlight scala %}
5557
val xs = Seq(
5658
foo,
57-
baz // This isn't going to work
59+
baz
5860
bar,
59-
)
61+
) // error: illegal start of simple expression
6062
{% endhighlight %}
6163

62-
### Reduce diff noise
64+
### Diff noise reduction
6365

64-
Allowing trailing commas also reduces a lot of noise in diffs, such as:
66+
Adding and removing commas also introduces unnecessary noise in diffs:
6567

6668
{% highlight diff %}
6769
@@ -4,7 +4,8 @@
68-
Map(
70+
Seq(
6971
foo,
7072
bar,
7173
- baz
@@ -76,15 +78,15 @@ Allowing trailing commas also reduces a lot of noise in diffs, such as:
7678

7779
### VCS authorship attribution
7880

79-
Using the example above, the authorship of the `baz` line would be preserved, instead of becoming that of the author of the `quux` line.
81+
Using the example above, adding a comma after `baz` also unnecessarily changed the authorship of the line.
8082

8183
### Simplify code generation
8284

83-
Such a feature would also simplify generating Scala source code.
85+
Allowing trailing commas would also simplify generating Scala source code.
8486

8587
### Long standing ticket
8688

87-
There is an open ticket ([SI-4986][]) where this feature was requested, referencing the fact that it facilitates code generation by tools and allows for easier sorting of the values, initially in the context of import selectors but later also for other constructs in the syntax.
89+
([SI-4986][]) was opened in 2011 requesting support for trailing commas, referencing that it facilitates code generation by tools and allows easier sorting of values. It was initially in the context of import selectors but later also for other constructs in the syntax.
8890

8991
### Real-world use-cases
9092

@@ -95,45 +97,120 @@ Some real-world use-cases where elements of a sequence are typically added, remo
9597

9698
## Design Decisions
9799

98-
There are a number of different elements of the Scala syntax that are comma separated, but instead of changing them all a subset of the more useful ones was chosen:
100+
### Multi-line
101+
102+
It is not the intent of introducing trailing commas to promote a code style such as:
103+
104+
{% highlight scala %}
105+
val xs = Seq(foo, baz, bar, )
106+
{% endhighlight %}
107+
108+
for a number of reasons:
109+
110+
1. Subjectively, it's an ugly style.
111+
2. Some people utilise commas as a mechanism for counting, so introducing an optional trailing commas interferes with this technique; when elements are one by line, then line-counting can be used.
112+
3. Adding or removing elements is less cumbersome on one line.
113+
4. Commenting out elements isn't any less cumbersome with an optional trailing comma.
114+
115+
Trailing comma support is therefore restricted to only comma-separated elements that are on separate lines:
116+
117+
{% highlight scala %}
118+
val xs = Seq(
119+
foo,
120+
baz,
121+
bar,
122+
)
123+
{% endhighlight %}
124+
125+
### What parts of the Scala grammar to change
126+
127+
There are a number of different parts of the Scala grammar that are comma-separated and, therefore, could support trailing commas. Specifically:
128+
129+
* `ArgumentExprs`
130+
* `Params` and `ClassParams`
131+
* `SimpleExpr1`
132+
* `TypeArgs`, `TypeParamClause` and `FunTypeParamClause`
133+
* `SimpleType` and `FunctionArgTypes`
134+
* `SimplePattern`
135+
* `ImportSelectors`
136+
* `Import`
137+
* `Bindings`
138+
* `ids`, `ValDcl`, `VarDcl`, `VarDef` and `PatDef`
99139

100-
* tuples
101-
* argument and parameter groups, including for implicits, for functions, methods and constructors
102-
* import selectors
140+
With this proposal I would like to present 2 variants:
103141

104-
From the spec these are:
142+
1. The first variant adds trailing comma support to only multi-line `ArgumentExprs`, `Params` and `ClassParams`, which I consider to be the parts of the grammar that would most benefit from trailing commas.
105143

106-
* SimpleExpr1, ArgumentExprs via Exprs
107-
* ParamClause, ParamClauses via Params
108-
* ClassParamClause, ClassParamClauses via ClassParams
109-
* ImportSelector
144+
2. The second variant adds trailing comma support to the whole grammar (again, only for multi-line), which means more consistency, but also supporting trailing commas in places that in practice don't really require it as much, such as `ids`.
110145

111-
The elements that have not changed are:
146+
In this proposal, only the first variant is considered: trailing comma support for `ArgumentExprs`, `Params` and `ParamClasses` for the sake of simplicity.
112147

113-
* ValDcl, VarDcl, VarDef via ids
114-
* Type via FunctionArgTypes
115-
* SimpleType, TypeArgs via Types
116-
* Expr, ResultExpr via Bindings
117-
* SimplePattern via Patterns
118-
* TypeParamClause, FunTypeParamClause
119-
* ImportExp
120-
* PatDef
148+
See below for more details on what that would mean.
149+
150+
#### Changing `ArgumentExprs`
151+
152+
**Spec change**
153+
154+
{% highlight diff %}
155+
Exprs ::= Expr {‘,’ Expr}
156+
-ArgumentExprs ::= ‘(’ [Exprs] ‘)’
157+
+ArgumentExprs ::= ‘(’ [Exprs] [‘,’] ‘)'
158+
{% endhighlight %}
159+
160+
**Example**
161+
{% highlight scala %}
162+
Seq(
163+
foo,
164+
bar,
165+
baz,
166+
)
167+
{% endhighlight %}
168+
169+
## `Params` and `ClassParams`
170+
171+
**Spec change**
172+
{% highlight diff %}
173+
Params ::= Param {‘,’ Param}
174+
- ParamClause ::= [nl] ‘(’ [Params] ‘)’
175+
-ParamClauses ::= {ParamClause} [[nl] ‘(’ ‘implicit’ Params ‘)’]
176+
+ ParamClause ::= [nl] ‘(’ [Params] [‘,’] ‘)’
177+
+ParamClauses ::= {ParamClause} [[nl] ‘(’ ‘implicit’ Params [‘,’] ‘)’]
178+
179+
ClassParams ::= ClassParam {‘,’ ClassParam}
180+
- ClassParamClause ::= [nl] ‘(’ [ClassParams] ‘)’
181+
-ClassParamClauses ::= {ClassParamClause} [[nl] ‘(’ ‘implicit’ ClassParams ‘)’]
182+
+ ClassParamClause ::= [nl] ‘(’ [ClassParams] [‘,’] ‘)’
183+
+ClassParamClauses ::= {ClassParamClause} [[nl] ‘(’ ‘implicit’ ClassParams [‘,’] ‘)’]
184+
{% endhighlight %}
185+
186+
**examples**
187+
{% highlight scala %}
188+
def bippy(
189+
foo: Int,
190+
bar: String,
191+
baz: Boolean,
192+
)
193+
194+
class Bippy(
195+
foo: Int,
196+
bar: String,
197+
baz: Boolean,
198+
)
199+
{% endhighlight %}
121200

122201
## Implementation
123202

124-
The implementation is a simple change to the parser, allowing for a trailing comma, for the groups detailed above, and has been proposed in [scala/scala#5245][].
203+
The implementation of trailing commas is is limited to changing Parsers.scala in the Scala compiler. An implementation of this proposal can be found at [scala/scala#5245][].
125204

126205
## Drawbacks/Trade-offs
127206

128-
The drawback, or trade-off, to this change is that it adds another way in which it is possible to do something in Scala. But it is the opinion of this SIP that the pragmatic advantage of being able to have trailing commas is worth this drawback.
207+
One drawback, or trade-off, to this change is that it adds an alternative way in which it is possible to do something in Scala. But I believe that the pragmatic advantage of being able to have trailing commas is worth this drawback.
129208

130-
Given that this is a change in syntax, another drawback is that it requires changing the existing tools, such as those that parse Scala: intellij-scala, scalariform, scala.meta and scalaparse.
209+
Another drawback, given this is a change in syntax, is that it requires changing the existing tools, such as those that parse Scala: intellij-scala, scalariform, scala.meta and scalaparse.
131210

132211
## Alternatives
133212

134-
As an alternative, trailing commas support could be added universally to all the comma-separated elements of the syntax. This would mean changing more (but still only in the parser), but it would make it consistent.
135-
136-
As an alternative to changing the language, there already exists today a compiler plugin called [scala-commas][] that provides this feature. It also provides some evidence that people would even use unsupported compiler apis and reflection to add this functionality, even when such a plugin won't compose with other plugins well, though arguably only weak evidence as it's a young and obscure plugin.
213+
As an alternative to changing the language, there already exists today a compiler plugin called [scala-commas][] that provides a variant of this feature. It also provides some evidence that people would even use unsupported compiler apis and reflection to add this functionality, even when such a plugin won't compose with other plugins well, though arguably only weak evidence as it's a young and obscure plugin.
137214

138215
## References
139216

@@ -144,3 +221,5 @@ As an alternative to changing the language, there already exists today a compile
144221
[SI-4986]: https://issues.scala-lang.org/browse/SI-4986
145222
[scala/scala#5245]: https://github.com/scala/scala/pull/524://github.com/scala/scala/pull/5245
146223
[scala-commas]: https://github.com/47deg/scala-commas
224+
[#533]: https://github.com/scala/scala.github.com/pull/533
225+
[#625]: https://github.com/scala/scala.github.com/pull/625

0 commit comments

Comments
 (0)