はじめに
この記事は スタンバイ Advent Calendar 2021 の13日目の記事です。
昨日の記事は @nnhiguchi さんの Amazon Rekognitionを使って静止画・動画の節度判定を省力化する でした。
#前提
この記事で引用させてもらっているコードは全てScala3マイグレーションガイドのものです。
#ごあいさつ
10月から株式会社スタンバイでSEOエンジニアをやっております、本田と申します!
スタンバイでは、Scalaを主に使用しています。
自分は今までpython, PHPなどスクリプト言語しか触ったことないので日々勉強の毎日ではありますが、
この度Scalaのキャッチアップもかねてアドベントカレンダーに参加させていただきました!
#和訳して読もうと思ったきっかけ
きっかけは、Scalaの勉強会を漁っていたところReactive System Meetupを見つけオンライン参加してみたのが初めです。
Seth TisueさんがScala2からScala3への変換について発表してくださったのを聞いて、
Scala3マイグレーションガイドの存在を知りました。
スタンバイのAPIではScala2系のフレームワークを使っているので将来Scala3に移行するのかも? と思い、そうなった時にマイグレーションガイドは読んでおいたほうがいいなと思い読み始めました。
日本語は用意されてないので、最初の方は頑張って英語で読んでいたのですが頭に入ってこなく、「これ、日本語訳して読めば、読み込むし内容はいってくるんじゃね?」と脳筋パワースタイルな発想で取り掛かりました。
#どんなことをしたのか
毎朝一時間早く席についてSlackにひたすら和訳していく、それだけです笑
こんな感じで、一日のはじめにScala3のマイグレーションガイドを読むというのが、11/8からはじまり、14日/人で和訳して読むということが終わりました。ここまでやって、「あれ、これOSSコミットできんじゃね?」ってことに気づき、2日かけてSlackにメモ書きしたものを、Scalaドキュメントをフォークしてブランチ切り日本語訳を移すという作業をしました。
この段階で意味的に問題ないか読み返しながら移植したので結果的に2回読みました苦笑
おかげで、内容は結構頭にはいってきて結果的にOSSコミットもでき、さらにスタンバイのアドベントカレンダーもかけるという一度で3つ美味しい状態になりました!
#成果物
早速成果物を共有していきたいと思います!
結果的に2つOSSのPRとissueを投げるこができました。1つは和訳したもの、もう1つは和訳する上で、「マークダウンの表の表記おかしくね?」となった軽微な修正、最後はビルドする上でリンク切れになっていたもののissue。
結果的に既存のドキュメントの不備も修正することができてよかったです
#やってよかったこと
和訳する上でやってよかったことは、自分はScalaのキャッチアップをscala-text.github.ioでやっていたのですが、その内容を超えるものに関して知ることができたというのが何より良かったです。
...
などなど自分の知らなかった言語機能についてキャッチアップできました。
あと前提として、 Scala2.13とScala3の移行について書かれているので、そもそも自分の関わっているプロジェクトがScala2.13以上なのか、とか、sbtのバージョンは1.5.0以上なのか、などアンテナを広げることができたのが良かった点だと思います。
#印象深いページ
ここまで来て内容について触れないのかよ!って言われそうなので、読んでて「何回もこの文書でてきたな」という印象に残ったところを上げていきたいと思います
##Scala 2.13とScala 3はお互いのアーティファクトに依存できる
クラスパスの互換性のページがまず印象深かったです。なにより、Scala2.13でScala3のオブジェクトをコンパイルして使うことができるんだということに感動しました。
lazy val foo = project.in(file("foo"))
.settings(scalaVersion := "3.0.0")
.dependsOn(bar)
lazy val bar = project.in(file("bar"))
.settings(scalaVersion := "2.13.6")
このようにScalaのバージョンを宣言時に指定することでコンパイルできるのはめちゃくちゃビックリしました。
逆にScala2.13をScala3で使う場合は
lazy val foo = project.in.file("foo")
.settings(
scalaVersion := "2.13.6",
scalacOptions += "-Ytasty-reader"
)
.dependsOn(bar)
lazy val bar = project.in(file("bar"))
.settings(scalaVersion := "3.0.0")
このように書けばコンパイルすることができます。
Scalaは全ての値がオブジェクトであるので、これができるのは相当移行が楽になるんじゃないでしょうか?と印象に残りました
##マクロの移行
マクロの移行ページも結構繰り返し説明されていて印象に残っています。
Scala3ではScala2のマクロ機能をゼロから作り直しているので、Scala2のマクロを移行する時は書き直ししなければならないということです。
理由としては、Scala 2.13のマクロAPIがScala 2.13コンパイラの内部依存しており、コンパイラ自体も刷新したScala 3コンパイラではScala 2.13マクロを展開することができないからです。
フレームワークとかで内部的につかっているマクロが今後どのように移行していくかは気になるポイントだと思います。
一応マイグレーションガイドにはビルドの方法が2通り記述されていました。
1つはScala2.13とScala3用で二回リリースを行う、クロスビルド方法で、バージョン固有のソースを専用のディレクトリをつくりそこに再配置してそれぞれコンパイルフェーズで使い分けるというものでした。
2つ目はミクシング(合成)でScala3のモジュールにScala2.13マクロとScala3のマクロを混ぜるものでした。Scala3コンパイルでScala2のマクロ展開はできないものの定義は読み込むことができるという点を利用しています。最終的に合成したものをScala2.13のアーティファクトに依存させれば使えるよというようなものが例示されいてすごく印象に残っています。
##シンタックスの変更
最後に、シンタックスの変更ページも印象に残っていたのでいくつか取り上げてみます。
###手続きシンタックスの型を明示的に示さないといけなくなった:
def print() { // Error: Procedure syntax no longer supported; `: Unit =` should be inserted here
println("bar")
}
これまでは返り値の型を省略しても型推論されていましたが、Scala3では明示的に置かないとエラーになります
object Bar {
def print(): Unit = {
println("bar")
}
}
これに関してはこちらのScala警察の発表資料にも省略することによるミスリードが説明されていました
###インデントが怒られるようになった:
インデントが今まで自由?にかけてたのが、Scala3ではエラーになるようになりました。
だんだんpythonに近づいている?とすこし思いました
def bar: (Int, Int) = {
val foo = 1.0
val bar = foo // [E050] Type Error: value foo does not take parameters
(1, 1)
} // [E007] Type Mismatch Error: Found Unit, Required (Int, Int)
###型パラメータとしての_が使えなくなった
これまでワイルドカードとしてつかっていた_
がScala3の型パラメータでは使えなくなっています。
-- [E040] Syntax Error: src/main/scala/anonymous-type-param.scala:4:10
4 | def foo[_: Foo]: Unit = ()
| ^
| an identifier expected, but '_' found
結構使っているソースあるのではないでしょうか?
こちらはもう使えなくて明示的にdef foo[T: Foo]: Unit = ???
みたいに記述する必要があります
##ちゃんとリライトオプションを用意してくれているところと全てオプショナルなところ
Scala3のコンパイラオプションでリライトオプションを使うとほぼ網羅的に古いシンタックスを書き換えしてくれるのが驚きです。
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.
日本語訳: 既存のScalaコードを手動で新しい構文に変換するのは面倒で、エラーが発生しやすくなります。
この章では、コンパイラを使用して、コードを従来のScala 2スタイルから新しいコードスタイルに、またはその逆について、自動的に書き換える方法を示します。
更に驚きなのは古いシンタックスに切り戻しできるオプションもあるということで、
シンタックスの書き換えページでScala3のインデントの書き換えごScala2の記述に戻して一周するというのが記述されていて印象に残りました。
Scala2ユーザのことをちゃんと考慮してくれるなんて本当にScala3の開発者さんは素晴らしいと感動しました。
#最後に
今回和訳することでScalaの言語仕様など、非常に勉強になったので次はAkkaなどのチュートリアルも読んでいこうかなと思っています!
明日は @Nisiさんの「【空冷自作PC】Ryzen7 5700G + ASRock DeskMini X300をノクチュア NH-P1でファンレスにした話」です!気になりますね!