From 5a0f5e176df23e0e535ea6e503e22f87e5657157 Mon Sep 17 00:00:00 2001 From: Adrien Piquerez Date: Wed, 30 Jun 2021 14:59:36 +0200 Subject: [PATCH 1/2] Rework syntax rewriting doc Give a bit more details about the new syntax. Make it clear that one must rewrite to the new control structure before rewriting to the indentation based syntax. Show the example in that order. Simplify the example (it is not a reference). --- .../tooling-syntax-rewriting.md | 138 +++++++----------- 1 file changed, 49 insertions(+), 89 deletions(-) diff --git a/_overviews/scala3-migration/tooling-syntax-rewriting.md b/_overviews/scala3-migration/tooling-syntax-rewriting.md index c7c77a68b8..1d6ac4a461 100644 --- a/_overviews/scala3-migration/tooling-syntax-rewriting.md +++ b/_overviews/scala3-migration/tooling-syntax-rewriting.md @@ -7,13 +7,16 @@ previous-page: tutorial-macro-mixing next-page: incompatibility-table --- -Scala 3 gives Scala developers the option to adopt the new and optional significant indentation syntax. -The Scala 2 syntax which uses curly braces to group expressions remains fully supported, and we will refer to it as the classical braces syntax. +Scala 3 extends the syntax of the Scala language with the new control structures and the significant indentation syntax. +Both are optional so that the Scala 2 code style is still perfectly valid in Scala 3. -Scala 3 also introduces a new syntax for control structures, which applies to `if`-expressions, `while`-loops, and `for`-expressions. +The new syntax for control structures makes it possible to write the condition of an `if`-expression, the condition of a `while`-loop or the generators of a `for`-expression without enclosing parentheses. -Converting existing code to use the new syntax by hand would be tedious and error-prone. -The good news is the Scala 3 compiler can do the hard work for us! +The significant indentation syntax makes braces `{...}` not needed in many occurences: class and method bodies, `if`-expressions, `match`-expressions and more. +You can find a complete description in the [Optional Braces](http://dotty.epfl.ch/docs/reference/other-new-features/indentation.html) page of the Scala 3 reference website. + +Converting existing Scala code to the new syntax by hand is tedious and error-prone. +In this chapter we show how you can use the compiler to rewrite your code automatically from the classic Scala 2 style to the new style, or conversely. ## Syntax Rewriting Options @@ -41,43 +44,33 @@ where possible standard options include: Each of the first four options corresponds to a specific syntax: +| Syntax | Option | +| - | - | +| New Control Structures | `-new-syntax` | +| Old Control Structures | `-old-syntax` | + | Syntax | Compiler Option | |-|-| | Significant Indentation | `-indent` | | Classical Braces | `-noindent` | -| Syntax | Option | -| - | - | -| New Control Structure | `-new-syntax` | -| Old Control Structure | `-old-syntax` | As we will see in further detail these options can be used in combination with the `-rewrite` option to automate the conversion to a particular syntax. Let's have a look at how this works in a small example. -## Significant Indentation Syntax +## The New Syntax Rewrites -Given the following source code written in the Scala 2 style: +Given the following source code written in a Scala 2 style. ```scala -object Counter { - enum Protocol { - case Reset - case MoveBy(step: Int) - } -} - -case class Animal(name: String) - -trait Incrementer { - def increment(n: Int): Int -} - case class State(n: Int, minValue: Int, maxValue: Int) { + def inc: State = if (n == maxValue) this else this.copy(n = n + 1) + def printAll: Unit = { println("Printing all") for { @@ -88,67 +81,60 @@ case class State(n: Int, minValue: Int, maxValue: Int) { } ``` -Assume that we want to convert this piece of code to the significant indentation syntax. -We can use the `-indent -rewrite` options by adding them to the `scalacOptions` setting in our sbt build: +We will be able to move it to new syntax automatically in two steps: first by using the new control structure rewrite (`-new-syntax -rewrite`) and then the significant indentation rewrite (`-indent -rewrite`). + +> The `-indent` option does not work on the classic control structures. +> So make sure to run the two steps in the correct order. + +> Unfortunately, the compiler is not able to apply both steps at the same time: `-indent -new-syntax -rewrite`. + +### New Control Structures + +We can use the `-new-syntax -rewrite` options by adding them to the list of scalac options in our build tool. ```scala // build.sbt -scalacOptions ++= Seq("-indent", "-rewrite") +scalacOptions ++= Seq("-new-syntax", "-rewrite") ``` After compiling the code, the result looks as follows: ```scala -object Counter: - enum Protocol: - case Reset - case MoveBy(step: Int) - -case class Animal(name: String) - -trait Incrementer: - def increment(n: Int): Int - -case class State(n: Int, minValue: Int, maxValue: Int): +case class State(n: Int, minValue: Int, maxValue: Int) { + def inc: State = - if (n == maxValue) + if n == maxValue then this else this.copy(n = n + 1) - def printAll: Unit = + + def printAll: Unit = { println("Printing all") - for { + for i <- minValue to maxValue j <- 0 to n - } println(i + j) + do println(i + j) + } +} ``` -A few things to observe after the switch to the significant indentation syntax: -- The number of lines was reduced by 4 because of the elimination of a series of closing curly braces -- The control structures are unchanged +Notice that the parentheses around the `n == maxValue` disappeared, as well as the braces around the `i <- minValue to maxValue` and `j <- 0 to n` generators. -## New Control Structure +### Significant Indentation Syntax -After this first rewrite, we can jump to the new control structure syntax by using `-new-syntax -rewrite`. +After this first rewrite, we can use the significant indentation syntax to remove the remaining braces. +To do that we use the `-indent` option in combination with the `-rewrite` option. It leads us to the following version: ```scala -object Counter: - enum Protocol: - case Reset - case MoveBy(step: Int) - -case class Animal(name: String) - -trait Incrementer: - def increment(n: Int): Int - case class State(n: Int, minValue: Int, maxValue: Int): + def inc: State = if n == maxValue then this else this.copy(n = n + 1) + def printAll: Unit = println("Printing all") for @@ -157,37 +143,22 @@ case class State(n: Int, minValue: Int, maxValue: Int): do println(i + j) ``` -We moved to the new syntaxes of Scala 3 in two steps: first we used `-indent -rewrite` then `-new-syntax -rewrite`. -We could also apply the new control structure syntax before the significant indentation syntax. -But the compiler is not able to apply both at the same time: `-indent -new-syntax -rewrite`. - -## Moving back to Classic syntax +## Moving back to the Classic syntax Starting from the latest state of our code sample, we can move backwards to its initial state. -Let's rewrite to the braces syntax and retain the new control structures syntax. +Let's rewrite the code using braces while retaining the new control structures. After compiling with the `-no-indent -rewrite` options, we obtain the following result: ```scala -object Counter { - enum Protocol { - case Reset - case MoveBy(step: Int) - } -} - -case class Animal(name: String) - -trait Incrementer { - def increment(n: Int): Int -} - case class State(n: Int, minValue: Int, maxValue: Int) { + def inc: State = if n == maxValue then this else this.copy(n = n + 1) + def printAll: Unit = { println("Printing all") for { @@ -202,25 +173,14 @@ case class State(n: Int, minValue: Int, maxValue: Int) { Applying one more rewrite, with `-old-syntax -rewrite`, takes us back to the original Scala 2-style code. ```scala -object Counter { - enum Protocol { - case Reset - case MoveBy(step: Int) - } -} - -case class Animal(name: String) - -trait Incrementer { - def increment(n: Int): Int -} - case class State(n: Int, minValue: Int, maxValue: Int) { + def inc: State = if (n == maxValue) this else this.copy(n = n + 1) + def printAll: Unit = { println("Printing all") for { From 167d0b34e905669d0083c8d5cffff71bf998d5f0 Mon Sep 17 00:00:00 2001 From: Adrien Piquerez Date: Tue, 10 Aug 2021 10:08:21 +0200 Subject: [PATCH 2/2] Update link to Scala 3 reference --- _overviews/scala3-migration/tooling-syntax-rewriting.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/_overviews/scala3-migration/tooling-syntax-rewriting.md b/_overviews/scala3-migration/tooling-syntax-rewriting.md index 1d6ac4a461..e4b3bcc9aa 100644 --- a/_overviews/scala3-migration/tooling-syntax-rewriting.md +++ b/_overviews/scala3-migration/tooling-syntax-rewriting.md @@ -13,7 +13,7 @@ Both are optional so that the Scala 2 code style is still perfectly valid in Sca The new syntax for control structures makes it possible to write the condition of an `if`-expression, the condition of a `while`-loop or the generators of a `for`-expression without enclosing parentheses. The significant indentation syntax makes braces `{...}` not needed in many occurences: class and method bodies, `if`-expressions, `match`-expressions and more. -You can find a complete description in the [Optional Braces](http://dotty.epfl.ch/docs/reference/other-new-features/indentation.html) page of the Scala 3 reference website. +You can find a complete description in the [Optional Braces](https://docs.scala-lang.org/scala3/reference/other-new-features/indentation.html) page of the Scala 3 reference website. Converting existing Scala code to the new syntax by hand is tedious and error-prone. In this chapter we show how you can use the compiler to rewrite your code automatically from the classic Scala 2 style to the new style, or conversely.