Magnolia Tech

いつもコードのことばかり考えている人のために。

Scala3学習メモ: 新しい制御記法

Scala3では、“quiet” syntaxと呼ばれるPythonっぽい新しい記法が導入されていて、括弧が大幅に削減できるようになっています。

おそらく一番大きな変化点ですね。Scala3ベースの解説書である『Programming in Scala Fifth Edition』もすべてのコード例がこの記法に置き換わっているので、今後は統一されていくのでしょう。

ifの条件式に括弧が不要になり、代わりに条件式の終わりを示すthenというキーワードを置きます

$ cat test.scala
@main def example =
  val x = 1
  if x == 1 then
    println("one")
$ scala test.scala
one

(はてなブログのカラーシンタックスは既にthenをキーワードとしてハイライトするようになっているようですね)

whileの条件式に括弧が不要になり、代わりに条件式の終わりを示すdoというキーワードを置きます

$ cat test.scala
@main def example =
  var x = 1
  while x != 0 do
    x -= 1
    println("one")
$ scala test.scala
one

forやtryでも同様です。

クラスやメソッド定義でも括弧が不要になりました

$ cat test.scala
@main def example =
  Hello.hello()

object Hello:
  def hello() =
    println("hello")
$ scala test.scala
hello

C言語風のシンタックスから大きく変えてきたのが驚きですが、従来の記法もまだ使えます。

また、従来の形式のソースファイルを、scalac [ファイル名] -rewrite -indentというオプションを与えると、コンパイルと同時に元のソースコードを新しい形式に書き換えてくれます(コメント等はちゃんと残ります)。

$ cat oldstyle.scala
package example

object Test {
  var answer = 42
  def hello(): Unit = {
    if (answer == 42) {
      println("hello")
    }
  }
}

$ scalac oldstyle.scala -rewrite -indent
[patched file oldstyle.scala]

$ cat oldstyle.scala
package example

object Test:
  var answer = 42
  def hello(): Unit =
    if (answer == 42)
      println("hello")

元に戻したいときは、 -rewrite -no-indentで書き換えられます。また、特に何のオプションも与えなければ、一つのソースコードの中で従来の記法と新しい記法が混在していても問題ありませんが、-old-syntaxや、-new-syntaxというオプションをセットすることで、記法を強制できます(異なる記法はコンパイルエラー)。

なお、インデントだけだと可読性が悪い(インデントの階層がネストしている、コードの行が長い)場合には、オプションとしてendというキーワードを差し込めます。rubyのendと違うのは、後ろに閉じたい内容を書かないといけないところです。ifを閉じるなら、end ifだし、fooというメソッドの定義を閉じたい時には、end fooとなります。従来のbraceであれば一発で対応関係を確認する方法がエディタに用意されていましたが、これでは独自のプラグインを書かないと分からないですね

package example

object Test:
  var answer = 42
  def hello(): Unit =
    if (answer == 42)
      println("hello")
      val x = 1
    end if
  end hello

公式ドキュメントには-rewrite -new-syntax-rewrite -old-syntaxで書き換えられる、という記載があるのですが、どうもできないようです(記述誤りか?)

なお、当然ですが、インデントの法則が完全に変わってしまうので、例えばvim-scalaのようなScala3に対応していないプラグインではインデントが崩れてしまいます。