Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Style Guide update #3122

Open
wants to merge 3 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 10 additions & 0 deletions _layouts/style-guide.html
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,16 @@
{{content}}
</div>

<div class="two-columns">
{% if page.previous-page %}
<a href="{{page.previous-page}}.html">&larr; <strong>previous</strong></a>
{% else %}
<div></div>
{% endif %}
{% if page.next-page %}
<a href="{{page.next-page}}.html"><strong>next</strong> &rarr;</a>
{% endif %}
</div>
{% include contributors-list.html %}
</div>
</div>
Expand Down
170 changes: 109 additions & 61 deletions _style/control-structures.md
Original file line number Diff line number Diff line change
@@ -1,33 +1,49 @@
---
layout: style-guide
title: Control Structures

partof: style
overview-name: "Style Guide"

overview-name: Style Guide
num: 7

previous-page: declarations
next-page: method-invocation
---

All control structures should be written with a space following the
defining keyword:

// right!
if (foo) bar else baz
for (i <- 0 to 10) { ... }
while (true) { println("Hello, World!") }

// wrong!
if(foo) bar else baz
for(i <- 0 to 10) { ... }
while(true) { println("Hello, World!") }

defining keyword. In Scala 3 parentheses around the condition should be omitted:

{% tabs control_structures_1 class=tabs-scala-version%}
{% tab 'Scala 2' for=control_structures_1 %}
```scala
// right!
if (foo) bar else baz
for (i <- 0 to 10) { ... }
while (true) { println("Hello, World!") }

// wrong!
if(foo) bar else baz
for(i <- 0 to 10) { ... }
while(true) { println("Hello, World!") }
```
{% endtab %}
{% tab 'Scala 3' for=control_structures_1 %}
```scala
// right!
if foo then bar else baz
for i <- 0 to 10 do ...
while true do println("Hello, World!")

// wrong!
if(foo) bar else baz
for(i <- 0 to 10) do ...
while(true) do println("Hello, World!")
```
{% endtab %}
{% endtabs %}

## Curly-Braces

Curly-braces should be omitted in cases where the control structure
In Scala 3 using curly-braces is discouraged and the quiet syntax with significant indentation is favoured.
In Scala 2, curly-braces should be omitted in cases where the control structure
represents a pure-functional operation and all branches of the control
structure (relevant to `if`/`else`) are single-line expressions.
Remember the following guidelines:
Expand All @@ -44,63 +60,84 @@ Remember the following guidelines:

<!-- necessary to separate the following example from the above bullet list -->

val news = if (foo)
goodNews()
else
badNews()

if (foo) {
println("foo was true")
}

news match {
case "good" => println("Good news!")
case "bad" => println("Bad news!")
}
{% tabs control_structures_2 class=tabs-scala-version%}
{% tab 'Scala 2' for=control_structures_2 %}
```scala
val news = if (foo)
goodNews()
else
badNews()

if (foo) {
println("foo was true")
}

news match {
case "good" => println("Good news!")
case "bad" => println("Bad news!")
}
```
{% endtab %}
{% tab 'Scala 3' for=control_structures_2 %}
```scala
val news = if foo then
goodNews()
else
badNews()

if foo then
println("foo was true")

news match
case "good" => println("Good news!")
case "bad" => println("Bad news!")
```
{% endtab %}
{% endtabs %}

## Comprehensions

Scala has the ability to represent `for`-comprehensions with more than
one generator (usually, more than one `<-` symbol). In such cases, there
are two alternative syntaxes which may be used:

// wrong!
for (x <- board.rows; y <- board.files)
yield (x, y)

// right!
for {
x <- board.rows
y <- board.files
} yield (x, y)
{% tabs control_structures_3 class=tabs-scala-version%}
{% tab 'Scala 2' for=control_structures_3 %}
```scala
// wrong!
for (x <- board.rows; y <- board.files)
yield (x, y)

// right!
for {
x <- board.rows
y <- board.files
} yield (x, y)
```
{% endtab %}
{% tab 'Scala 3' for=control_structures_3 %}
```scala
// wrong!
for x <- board.rows; y <- board.files
yield (x, y)

// right!
for
x <- board.rows
y <- board.files
yield (x, y)
```
{% endtab %}
{% endtabs %}

While the latter style is more verbose, it is generally considered
easier to read and more "scalable" (meaning that it does not become
obfuscated as the complexity of the comprehension increases). You should
prefer this form for all `for`-comprehensions of more than one
generator. Comprehensions with only a single generator (e.g.
`for (i <- 0 to 10) yield i`) should use the first form (parentheses
`for i <- 0 to 10 yield i`) should use the first form (parentheses
rather than curly braces).

The exceptions to this rule are `for`-comprehensions which lack a
`yield` clause. In such cases, the construct is actually a loop rather
than a functional comprehension and it is usually more readable to
string the generators together between parentheses rather than using the
syntactically-confusing `} {` construct:
Comment on lines -85 to -89
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I suggest to drop this since the arguments for using one-generator-per-line syntax hold no matter whether the next keyword is do or yield


// wrong!
for {
x <- board.rows
y <- board.files
} {
printf("(%d, %d)", x, y)
}

// right!
for (x <- board.rows; y <- board.files) {
printf("(%d, %d)", x, y)
}

Finally, `for` comprehensions are preferred to chained calls to `map`,
`flatMap`, and `filter`, as this can get difficult to read (this is one
of the purposes of the enhanced `for` comprehension).
Expand All @@ -111,11 +148,22 @@ There are certain situations where it is useful to create a short
`if`/`else` expression for nested use within a larger expression. In
Java, this sort of case would traditionally be handled by the ternary
operator (`?`/`:`), a syntactic device which Scala lacks. In these
situations (and really any time you have a extremely brief `if`/`else`
situations (and really any time you have an extremely brief `if`/`else`
expression) it is permissible to place the "then" and "else" branches on
the same line as the `if` and `else` keywords:

val res = if (foo) bar else baz
{% tabs control_structures_4 class=tabs-scala-version%}
{% tab 'Scala 2' for=control_structures_4 %}
```scala
val res = if (foo) bar else baz
```
{% endtab %}
{% tab 'Scala 3' for=control_structures_4 %}
```scala
val res = if foo then bar else baz
```
{% endtab %}
{% endtabs %}

The key here is that readability is not hindered by moving both branches
inline with the `if`/`else`. Note that this style should never be used
Expand Down
Loading