9月7日、Scala開発チームは、Scala 3.0.2の正式リリースを発表した。
リリース済みのScala 3.0.2-RC2に重大なバグがなかったため、3.0.2に昇格し、現在のScala安定版となった。
3.0.2の主な変更点
開発チームは、3.0.2で導入された最も重要な変更点の概要を紹介している。
最新リリースですべてのユーザーに提供される安定した機能に焦点を当てた内容にしたようだ。
論理条件でのセミコロン挿入の改善
Scala 3のインデントベースの構文は、コードをより簡潔で読みやすいものにすることを目的としている。
このシステムが広く採用されるようになると、直観的でない動作につながる可能性のあるケースを排除するために、一貫して仕様を改善している。
#12801のおかげで、if文や式の中の論理式がifキーワードと同じ行で始まる場合、次の行に続けることができるようになった。
if foo
(bar)
then //...
もし、コードブロックが単一の条件で評価されることを意図しているのであれば、ifの直後に改行してインデントを加えるべきだ。
if
val cond = foo(bar)
cond
then
そのため、以下のようなコードは無効となる。
if val cond = foo(bar)
cond
then
型システムにおけるnullの安全性向上を目指して
コンパイラオプションの "-Yexplicit-nulls" は、Scalaの標準的な型階層を変更し、型システムのレベルで直接厳密なチェックを行うことで、Nullableな値の追跡を容易にする。
("val foo: Option[String] = Some(null)"のようなコードを書くことはできない。これは有効なScalaではあるが、どこかで "NullPointerException" を引き起こす可能性がある。)
最近導入されたこのオプションを有効にすると、Null型はAnyを直接継承するのではなく、Matchableのサブタイプになり、以下のコードがコンパイルされるようになった。
(これまでは、厳密なnullabilityチェックを行わないとコンパイルできなかった。)
def foo(x: Matchable) = x match { case null => () }
タイプシグネチャーによるメソッド検索
ScalaのAPIドキュメントが、Inkuireとの統合により、メソッド名だけでなくタイプ別にHoogleのような方法で(ただしScalaの構文で)閲覧できるようになった。(#12375)
構造的型のための回避策
構造的型は、静的な型付けの安全性と、動的に変化するドメインデータ構造のスキーマを扱う際の使いやすさを両立させたい場合など、さまざまな場面で便利に活用できる。
しかし、いくつかの制限がある。
特に構造的型付けは、通常、メソッドのオーバーロードとは相性が良くない。
なぜなら、ある種のリフレクティブディスパッチアルゴリズム(JVMリフレクションを含む)は、消去後のパラメータの正確な型を前もって知らないと、正しいシグネチャを持つオーバーロードメソッドの代替を選択できない可能性があるからだ。
次のようなコードを考えてみる。
class Sink[A] { def put(x: A): Unit = {} }
val a = Sink[String]()
val b: { def put(x: String): Unit } = a
このコードはコンパイルされない。
これは、Sink[String]がSink[Object]に消去されると(JVMの視点では)、メソッドのシグネチャがput(x: Object): Unitとなるが、構造的型の場合は、put(x: String): Unitと変更されず、実行時に一致しない。
したがって、Sink[String]は、{ def put(x: String): Unit }のサブタイプとして扱うことはできない.
コンパイラに私達が何をしているのか分かっていることを保証するために、新しい"Selectable.WithoutPreciseParameterTypes"を使用する必要がある。
現在は実験的な機能(#12268)なので、スナップショットまたはnightly版のコンパイラでのみ使用することができ、この形質のすべてのサブタイプに@experimentalを付ける必要がある。
import annotation.experimental
@experimental trait MultiMethodSelectable extends Selectable.WithoutPreciseParameterTypes:
def applyDynamic(name: String, paramTypes: Class[_]*)(args: Any*): Any = ???
@experimental class Sink[A] extends MultiMethodSelectable:
def put(x: A): Unit = {}
val a = new Sink[String]
val b: MultiMethodSelectable { def put(x: String): Unit } = a
このコードは、コンパイラがbの正確なシグネチャチェックを行わなくなったため、コンパイルされる。
その他の変更
scala 3.0.2では、メタプログラミングを中心としたいくつかの小さな改良と、いくつかのバグの修正が行われた。
詳細な変更履歴はGitHubを参照。
今後について
私たちは、Scala 3の初期リリース後、最初のマイナーバージョンを出すのに適切な時期であると判断し、
3.0.2の安定版と合わせて、Scala 3.1の最初のリリース候補を発表した。
すでに3.1.0-RC1を使用することができ、より安全な例外のような実験的な新機能だけでなく、
Scaladocページに埋め込まれたScastie、JVMバイトコード生成の改善、コンパイラの警告設定の可能性、その他多くの小さな改善と修正を全体的にテストすることができる。
3.1.0-RC1の完全な変更履歴はGitHubで閲覧できる。
Scala 3.1の安定版リリースは、10月中旬を予定している。