これは Scala Advent Calendar 2023
の16日目です。
(あとから見たらこの日付が抜けていたので、あとから登録して埋めました)
これ書いている2023年12月現在、(RCなどの安定版以外も含めると) 3.4.0-RC1が最新で、3.4.0のfinalは出ていませんが、3.4.0から色々と変更点があるみたいなので、3.4.0-RC1時点の情報をざっくりまとめます。
あくまで自分が遭遇した、あるいはざっくりリリースノート見て書き出しただけなので、他にも大量にありそうですが、ひとまずこの程度にしておきます。
https://github.com/lampepfl/dotty/releases/tag/3.4.0-RC1
各種書き換えは、scalafmtの設定だけで可能な場合もあるし、scalafixでやった方がいいパターンもあり得るかもしれないし、あるいは、(現状でも?少し待てば?)Scala 3自体の -rewrite
オプションでやってくれるパターンもありそうですが、そこの詳細については調べきれてないので、今回はまとめません。
また、細かいコンパイルオプションの指定の有無によって細かい挙動は変わるはずですが、あくまで何も指定してないのに警告やエラーが増えるパターンについて書いています。
また、大抵はScala 2で -Xsource:3
付与すれば、Scala 2と3でのcross buildは、新しい記法に揃える方法で、困らないようになってるはず・・・(一部を除く)
ワイルドカードで _
が非推奨
- https://github.com/lampepfl/dotty/pull/18813
_
ではなく?
使いましょう
Welcome to Scala 3.4.0-RC1 (11.0.21, Java OpenJDK 64-Bit Server VM). Type in expressions for evaluation. Or try :help. scala> val xs: List[_] = Nil 1 warning found -- Warning: -------------------------------------------------------------------- 1 |val xs: List[_] = Nil | ^ | `_` is deprecated for wildcard arguments of types: use `?` instead val xs: List[?] = List() scala> val xs: List[?] = Nil val xs: List[?] = List()
private[this]
や protected[this]
が非推奨
- 単純に
[this]
部分を消しましょう - https://docs.scala-lang.org/scala3/reference/dropped-features/this-qualifier.html
- https://github.com/lampepfl/dotty/pull/18819
Welcome to Scala 3.4.0-RC1 (11.0.21, Java OpenJDK 64-Bit Server VM). Type in expressions for evaluation. Or try :help. scala> class A { protected[this] def x = 2 } 1 warning found -- Warning: -------------------------------------------------------------------- 1 |class A { protected[this] def x = 2 } | ^ |The [this] qualifier will be deprecated in the future; it should be dropped. |See: https://docs.scala-lang.org/scala3/reference/dropped-features/this-qualifier.html
初期化されてない var
の値を表現するのに _
が非推奨
- https://github.com/lampepfl/dotty/pull/18821
- uninitializedという特別なメソッドがScala 3からあるのでそれ使いましょう
- Scala 2と3でcross buildしたい場合は・・・???
Welcome to Scala 3.4.0-RC1 (11.0.21, Java OpenJDK 64-Bit Server VM). Type in expressions for evaluation. Or try :help. scala> var a: String = _ 1 warning found -- Warning: -------------------------------------------------------------------- 1 |var a: String = _ | ^ | `= _` has been deprecated; use `= uninitialized` instead. | `uninitialized` can be imported with `scala.compiletime.uninitialized`. var a: String = null
型として with
を使うの非推奨
Welcome to Scala 3.4.0-RC1 (11.0.21, Java OpenJDK 64-Bit Server VM). Type in expressions for evaluation. Or try :help. scala> trait A; trait B // defined trait A // defined trait B scala> def x: A with B = new A with B {} 1 warning found -- [E003] Syntax Warning: ------------------------------------------------------ 1 |def x: A with B = new A with B {} | ^^^^ | with as a type operator has been deprecated; use & instead | | longer explanation available when compiling with `-explain` def x: A & B scala> def x: A & B = new A with B {} def x: A & B
可変長引数に対しての古い記法が非推奨
- https://github.com/lampepfl/dotty/pull/18872
: _*
ではなく*
になりました
Welcome to Scala 3.4.0-RC1 (11.0.21, Java OpenJDK 64-Bit Server VM). Type in expressions for evaluation. Or try :help. scala> val xs = (1 to 10) val xs: scala.collection.immutable.Range.Inclusive = Range 1 to 10 scala> List(xs : _*) 1 warning found -- Warning: -------------------------------------------------------------------- 1 |List(xs : _*) | ^ |The syntax `x: _*` is no longer supported for vararg splices; use `x*` instead val res0: List[Int] = List(1, 2, 3, 4, 5, 6, 7, 8, 9, 10) scala> List(xs *) val res1: List[Int] = List(1, 2, 3, 4, 5, 6, 7, 8, 9, 10)
eta expansion時の _
付与が非推奨
Welcome to Scala 3.4.0-RC1 (11.0.21, Java OpenJDK 64-Bit Server VM). Type in expressions for evaluation. Or try :help. scala> def x = identity[Int] _ 1 warning found -- Warning: -------------------------------------------------------------------- 1 |def x = identity[Int] _ | ^^^^^^^^^^^^^^^ | The syntax `<function> _` is no longer supported; | you can simply leave out the trailing ` _` def x: Int => Int scala> def x = identity[Int] def x: Int => Int
infixで定義してないメソッドをinfix記法で呼ぶと警告
- Scala 3からinfix defという定義ができるようになっていましたが、それが本格運用される的な
- infixとは日本語だと中置記法、以下のようにドット
.
と括弧(
)
を省略できる記法です - つまり
obj.method(arg)
がobj method arg
と書ける記法 infix def
で定義する、定義されてないならinfixの記法で呼ぶのやめる(括弧とドットを付与して普通に呼ぶ)、バッククオートで囲う、のいずれかをしましょう-Xsource:3
指定すればScala 2でもinfix def
自体の記法は許可されます
Welcome to Scala 3.4.0-RC1 (11.0.21, Java OpenJDK 64-Bit Server VM). Type in expressions for evaluation. Or try :help. scala> object A { | def foo(x: Int): Int = x + 3 | infix def bar(x: Int): Int = x + 10 | } // defined object A scala> A foo 2 1 warning found -- Warning: -------------------------------------------------------------------- 1 |A foo 2 | ^^^ |Alphanumeric method foo is not declared infix; it should not be used as infix operator. |Instead, use method syntax .foo(...) or backticked identifier `foo`. val res0: Int = 5 scala> A.foo(2) val res1: Int = 5 scala> A `foo` 2 val res2: Int = 5 scala> A bar 2 val res3: Int = 12
for式でパターンマッチしてる場合に case
がないとエラーに
- 3.3時点で、既に警告でしたが、3.4からはデフォルトではエラーになるようです
- https://github.com/lampepfl/dotty/pull/18842
3.3なら、デフォルトはまだ警告
Welcome to Scala 3.3.1 (11.0.21, Java OpenJDK 64-Bit Server VM). Type in expressions for evaluation. Or try :help. scala> for { (1, a) <- Option((2, "aaa")) } yield a 1 warning found -- Warning: -------------------------------------------------------------------- 1 |for { (1, a) <- Option((2, "aaa")) } yield a | ^ |pattern's type (1 : Int) is more specialized than the right hand side expression's type Int | |If the narrowing is intentional, this can be communicated by adding the `case` keyword before the full pattern, |which will result in a filtering for expression (using `withFilter`). val res0: Option[String] = None
3.4だとエラー
Welcome to Scala 3.4.0-RC1 (1.8.0_392, Java OpenJDK 64-Bit Server VM). Type in expressions for evaluation. Or try :help. scala> for { (1, a) <- Option((2, "aaa")) } yield a -- Error: ---------------------------------------------------------------------- 1 |for { (1, a) <- Option((2, "aaa")) } yield a | ^ |pattern's type (1 : Int) is more specialized than the right hand side expression's type Int | |If the narrowing is intentional, this can be communicated by adding the `case` keyword before the full pattern, |which will result in a filtering for expression (using `withFilter`). 1 error found scala> for { case (1, a) <- Option((2, "aaa")) } yield a // case付与すると通る val res0: Option[String] = None
追記
昨日blog書いた件、
— Kenji Yoshida (@xuwei_k) December 24, 2023
可変長引数とワイルドカードに関しては、以下のscalafmt設定で完全自動で揃えることが出来るはず。
しかも -Xsource:3 加えれば2.12や2.13とのcross build維持しつつあまり余計な部分書き変わらないはず? pic.twitter.com/uKlh8Yt5zb