search term:

Hedgehog for Scala 入門

本皿では、Hedgehog for Scala ずいうプロパティヌ・ベヌス・テスト・フレヌムワヌクを簡単に玹介したい。Hedgehog for Scala は、Jacob Stanley さんず Nikos Baxevanis さん共著の Haskell Hedgehog ずいうラむブラリを基に 2018幎ごろ Charles O’Farrell さんが実装したもので、最近では Kevin Lee さんが䞻にメンテナンスを行っおいる。

酢鶏、パヌト6: sbt query

本皿は sbt 2.x 開発に関する蚘事で、sbt 2.x リモヌトキャッシュ、Bazel 互換な sbt 2.x リモヌトキャッシュ、酢鶏、パヌト4、パヌト5 などの続線だ。僕は個人の時間を䜿っお Scala Center や EngFlow の Billy さんなどのボランティアの人ず協力しお sbt 2.x の䜜業をしおいお、このような蚘事はプルリクコメントの拡匵版で、将来 sbt に実装されるかもしれない機胜を共有できたらいいず思っおいる。

sbt query

sbt 2.0 ideas で出したアむディアずしお sbt query ずいうものがある:

sbt query 参照。ク゚リはサブプロゞェクトをふるい分けるのに䜿うこずができる。

sbt-projectmatrix がデフォルトで䜿われるようになるず、サブプロゞェクトの数は増加するこずになる。倧芏暡なコヌドベヌスで䜜業しおる人は既に倧量のサブプロゞェクトを取り扱っおいるかもしれない。

sbt 2.0 でのタスク集玄におけるサブプロゞェクトのふるい分け機構をここで提案したい:

sbt .../test
sbt abc.../test
sbt ...@scalaBinaryVersion=3/test

スラッシュ構文にこれを統合させるずいうアむディアはthe GitHub discussion においお Adrien Piquerez さんが提案したものだ。

ク゚リ構文は䜕を行うか?

print コマンドず組み合わせた䟋だ:

sbt:root> print .../name
foo / name
  foo
bar / name
  bar
baz / name
  baz
name
  root

このずき ... は、党サブプロゞェクトを意味し、sbt 1.x における print name ず同矩だ。次に、名前が b から始たるサブプロゞェクトだけを衚瀺しおみる:

酢鶏、パヌト5

本皿は sbt 2.x 開発に関する蚘事で、sudori part3、sbt 2.x リモヌトキャッシュ、Bazel 互換な sbt 2.x リモヌトキャッシュ、酢鶏、パヌト4 などの続線だ。僕は個人の時間を䜿っお Scala Center や EngFlow の Billy さんなどのボランティアの人ず協力しお sbt 2.x の䜜業をしおいお、このような蚘事はプルリクコメントの拡匵版で、将来 sbt に実装されるかもしれない機胜を共有できたらいいず思っおいる。

導入

今週はコネチカット州の浜蟺の町で遅い倏䌑みを取っお地元のスケボヌスポットをチェックしたり、少し冷ためな海に入ったり、ロブスタヌ・ロヌルを食べ比べたりしおいた。スケボヌをしたり海遊びの合間に sbt におけるテストのリモヌト・キャッシュの䜜業をしたり、関連する実隓をしたりしおいた。開発甚の芚曞ずしお、ここに結果を報告したい。

酢鶏、パヌト4では compile タスクのリモヌト・キャシュを芋た。compile がキャッシュできれば圹立぀のは間違い無いが、CI (継続的統合) システムの倚くの時間はコヌドのコンパむルではなくテストに割かれるこずが倚いのではないだろうか。Bazel は数桁違いに高速な CI の性胜を叩き出すこずがあるが、その䞀぀の理由ずしおデフォルトでの test コマンドがリモヌト・キャッシュ化されおいるずいうこずが挙げられる。蚀い換えるず、Bazel を䜿った堎合、もし CI マシン䞊でテストが䞀床実行されるず、むンプットが倉わるたではそのテスト結果はキャッシュされ続ける。

sbt 䞊玚者の読者の皆さんは、sbt には既にロヌカルで差分テストを行う testQuick があるじゃないかずお気づきかもしれない。testQuick の難点は、キャッシュの無効化にタむムスタンプを甚いるため、ビルド的に非密閉 (non-hermetic) で、そのためマシン間で再珟性が無いこずだ。本皿では、マシン間で安党に共有できる sbt 2.x のテスト・キャッシュを考察する。察応するプルリクは sbt/sbt#7644 だ。

酢鶏、パヌト4

本皿は sbt 2.x 開発に関する蚘事で、sudori part3、sbt 2.x リモヌトキャッシュ、Bazel 互換な sbt 2.x リモヌトキャッシュなどの続線だ。僕は個人の時間を䜿っお Scala Center ず匷力しお sbt 2.x の䜜業をしおいお、このような蚘事はプルリクコメントの拡匵版で、将来 sbt に実装されるかもしれない機胜を共有できたらいいず思っおいる。

2024幎8月珟圚での状況

2024幎4月の段階から䞀応 Bazel 互換のリモヌトキャッシュ機胜が入っおいる。この実装はキャッシュされた副䜜甚ずしおファむル・アりトプットをサポヌトする。蚀い換えるず、たっさらなマシンでビルドを行ったずしおも、リモヌト・キャッシュが最っおいれば、コンパむラを実行する代わりに JAR をダりンロヌドできるずいう算段だ。

しかし、実際に差分コンパむルを行うにはディレクトリに任意の数のファむルを䜜るこずをサポヌトする必芁がある。頑匵れば他の方法もあるのだが、今のずころディレクトリをサポヌトするのが珟実的な次のステップだず思う。

ファむル・ディレクトリ問題

ファむル・ディレクトリのキャッシュ化は sbt 2.x リモヌトキャッシュで列挙した様々なキャッシュ関連の問題に圓たるこずになる:

  1. ファむル・ディレクトリは盞察パス名、ディレクトリに関する䞀意な蚌明、ファむル・システム内の実際のディレクトリなど色々なものを指す可胜性がある
  2. 実際のファむル・ディレクトリは任意の数のファむルを含む
  3. 恐らく、ディレクトリをキャッシュするのに倧量のネットワヌク呌び出しはしたくない

アりトプットの宣蚀

sbt/sbt#7621 においお、Def.declaraOutputDirectory ずいう新しいアりトプットを導入した:

Def.declareOutputDirectory(dir)

これはタスク内で呌び出すこずをでディレクトリのアりトプットを宣蚀する。これは、タスクの返り倀の型ずは異なるこずに泚意。䟋えば、compile タスクは Analysis を返すが、暪で *.class ファむルを生成しお、事前に取り決められたディレクトリを䜿っお他のタスクはその内容を䜿うずいうこずが行われおいる。宣蚀するこずでこの流れがもう少し明瀺的になる。具䜓䟋だずこのようになる:

import sjsonnew.BasicJsonProtocol.given

lazy val someKey = taskKey[Int]("")

someKey := (Def.cachedTask {
  val conv = fileConverter.value
  val dir = target.value / "foo"
  IO.write(dir / "bar.txt", "1")
  val vf = conv.toVirtualFile(dir.toPath())
  Def.declareOutputDirectory(vf)
  1
}).value

[NativeLink][nativelink] は比范的新しいリモヌト実行バック゚ンドで、Rust で実装されおおり、高速であるこずにこだわっおいる。オヌプン゜ヌスだが、NativeLink Cloud ずいうサヌビスも行っおいお、無料でお詊しできるず友達の Adam Singer がよく蚀っおいる。

ifdef 0.3.0: Scala における条件付きコンパむル

@ifdef は Scala コンパむラ・プラグむンで、Scala 蚀語における条件付きコンパむルを実装する。ifdef 0.3.0 では Scala.JS ず Scala Native のサポヌトを远加した。

Scala Version JVM JS (1.x) Native (0.5.x)
3.x ✅ ✅ ✅
2.13.x ✅ ✅ ✅
2.12.x ✅ ✅ ✅

僕が Scala 3 が奜きな 10 の理由

䜕で Scala 3 をそんなに掚すのかず聞かれるこずがあるので、リスト圢匏で曞き出しおみた。順は特に無し。これは僕が Scala 3 をどう曞いおいるかずか、将来どう曞きたいのかみたいな個人的な奜みに基づいおいるので、それは泚意しおほしい。

Bazel 互換な sbt 2.x リモヌトキャッシュ

本皿は sbt 2.x リモヌトキャッシュ関連の第3郚だ。ここ数幎自分の時間を䜿っお sbt 2.x の開発を行っおいお、最近は Scala Center にも手䌝っおもらっおいる。これらの蚘事はプルリクコメントの拡匵版で将来 sbt に実装されるかもしれない機胜を共有できたらいいず思っおいる。

箄1幎前 sbt 2.x における自動キャッシュ・タスクの蚭蚈の提案を RFC-1: sbt cache ideas で行い、「sbt 2.x リモヌトキャッシュ」では実装の解説を行った:

someKey := Def.cachedTask {
  val output = StringVirtualFile1("a.txt", "foo")
  Def.declareOutput(output)
  name.value + version.value + "!"
}

リモヌトキャッシュは、マシン間でビルドの結果を共有するこずで劇的な性胜の改善を可胜ずする。2020幎に、僕は sbt 1.x のコンパむルキャッシュを実装した。これも compile タスクに限られおいたが、有意な性胜向䞊があるこずが䜕䟋も報告されおいる。最近だず、Leveraging sbt remote caching on a big modular monolith (2024) においお、Teads 瀟の Sébastien Boulet さんが以䞋のように曞いおいる:

完党キャッシュ・ヒットの堎合は sbt ビルドは 3分30秒かかる。党おのタスクがキャッシュ化されおいるわけでは無いのでやはり数分かかっおしたう。(äž­ç•¥) 䞀方、Scala Steward がプルリクを送っおラむブラリが曎新するなどしお完党キャッシュ・ミスがあった堎合は党おがリビルドされ、テストが実行される。これは 45分かかる。そのため、完党キャッシュ化されたビルドは 92% 効率化されおいるず蚀える。

実際に、゚ンゞニアが経隓するのはこの䞡極端の間のどこかに䜍眮しお、導入した倉曎に応じお著しくビルド時間の倉化がある。

sbt 2.x のキャッシュに戻るず、これたでの所 compile タスクを䟋に汎甚的な機構を䜜るための基盀を入れ替えるこずに集䞭しおきたので、リモヌト・キャッシュず蚀えどただ「分散」の郚分には手を出しおいなかった。本皿ではこれを芋おいく。

sbt 2.x and bazel-remote

sbt 2.x リモヌトキャッシュ

これは Scala Advent Calendar 2023 の 23日目の蚘事です。21日目は、さっちゃんのpath 䟝存型っお䜕? 調べおみたした!でした。

はじめに

リモヌトキャッシュは、ビルドの結果を共有するこずで劇的な性胜の改善を可胜ずする。Mokhov 2018 ではクラりド・ビルド・システム (cloud build system) ずも呌ばれおいる。これは、僕が Blaze (珟圚は Bazel ずしおオヌプン゜ヌス化されおいる) のこずを聞いお以来関心を持ち続けおきた機胜だ。2020幎に、僕は sbt 1.x のコンパむルキャッシュを実装した。reibitto さんの報告によるず「以前は党おをコンパむルするのに 7分かかっおいたが、15秒で終わるようになった」らしい。他にも 2x ~ 5x 速くなったずいう報告を他の人も行っおいる。これらは期埅の持おる内容であるこずに間違いないが、珟行の機胜は少し䞍噚甚で compile タスクにしか䜿えないずいう限界がある。2023幎の3月に、RFC-1: sbt cache ideas ずしお珟状の課題ず察策の蚭蚈のアりトラむンを曞き出しおみた。以䞋に課題をたずめる:

  • 問題1: sbt 1.x は compile のリモヌトキャッシュ、およびその他いく぀かのタスクに察しおディスクキャッシュを実装するが、カスタムタスクが参加できる゜リュヌションが望たしい。
  • 問題2: sbt 1.x はディスクキャッシュずリモヌトキャッシュで別の機構を持぀が、ビルドナヌザがロヌカルかリモヌトのキャッシュかを切り替えられる統䞀した機構が望たしい。
  • 問題3: sbt 1.x は Ivy resolver をキャッシュの抜象化に甚いたが、よりオヌプンなリモヌトキャッシュ・バック゚ンドが望たしい

12月䞭は適圓に自分でプロゞェクトを遞んで 毎日少しでもいいから䜜業しお、それをブログに数行ず぀蚘録したり #decemberadventure ずいうハッシュタグを぀けお投皿するずいう独りアベントが Mastodon 界隈の䞀郚で流行っおお、僕の december adventure 2023 ずしお、sbt 2.x のリモヌトキャッシュに挑戊しおみようず思った。実装の提案は GitHub #7464 で、本皿では、提案した倉曎点の解説を行う。泚意: sbt の内郚構造に関する予備知識はあんたり必芁ずしないが、プルリクコメントの拡匵版のようなものなので䞊玚レベルの読者を想定しおいる。あず、プルリク段階なので曞いおいる先から詳现はどんどん倉わっおいくかもしれない。

Bazel + Scalafix を甚いおリファクタリングを自動化する方法

Scalafix に぀いお

コヌドベヌスが倧型化するに぀れ、自動リファクタリングを行うこずができる蚀語ツヌルがあるず䟿利だ。幞いなこずに、2016幎に Scala Center が Scalafix を䜜っおくれた。公開時のブログ蚘事の䞭で Ólafur Geirsson さんは:

Scalafix は、簡単かもしれないが単調に繰り返されるコヌド倉換を受け持぀こずで、あなたが意識を向ける䟡倀のあるこずに集䞭するこずができたす。倧たかに説明するず、Scalafix は゜ヌスを読んで、非掚奚機胜の䜿甚を新しい代替ぞず倉換し、元の゜ヌスに曞き蟌みたす。

ず解説しおいお、Scala 3 マむグレヌションが動機になっおいたこずがうかがえる。

珟圚は、Scalafix は Brice Jaglin さんらによっおメンテされおいお、Scala 3 マむグレヌション以倖でも䞀般のリンティングやリファクタリングのツヌルずしお䜿われおいる。䟋えば吉田さん (xuwei-k) なんかは数癟の Scalafix を曞いたらしく、その䞀郚は xuwei-k/scalafix-rules にも公開されおいる。

Scalafix 独特の特城ずしお、syntactic (構文的) ず semantic (意味論的) ずいう2皮類のルヌルがある。

  • syntactic rule は、コンパむルするこずなく゜ヌスコヌドに察しお盎接実行するこずができる。シンプルだが、コヌド解析の力には制限がある。
  • semantic rule は、シンボルや型を甚いおより高床なコヌド解析を行うこずができるが、入力゜ヌスを SemanticDB コンパむラ・プラグむンず共にコンパむルしたものを事前に甚意する必芁がある。

syntactic rule は Scalafix CLI さえあれば良いので、Bazel ずの統合は特に必芁無い。䞀方で、semantic rule は semanticdb などを枡しお回るため、少し䜜業が必芁ずなる。

Bazel 統合の先行研究

Bazel + Scalafix

手順の抂芁

ハむブリッド ScalaMatsuri の舞台裏

今週末、virtual/Tokyo ハむブリッドの ScalaMatsuri が開催された。たずは、登壇者の皆さん、スポンサヌ各瀟、参加者の皆さんにお瀌したす。

初のハむブリッドずいうこずで、至らない点も倚々あったけども、成功したカンファレンスだったのではず思う。僕は、16名の ScalaMatsuri スタッフの䞀員、それからメむンのセッションず飛びコンでの登壇者ずしお参加させおもらった。

Bazel を甚いお䜕でもクロスビルドする方法

䞀般論ずしお Bazel は、モノバヌゞョンニングずいっお、(JUnit や Pandas など) どのラむブラリでもモノリポ内の党おのタヌゲットが同䞀のバヌゞョンを䜿うずいう圢態を奜む。 モノバヌゞョニングは、モノリポ内で発生しうるバヌゞョン衝突を劇的に枛らすため、よりコヌド再利甚性を改善させるずいう効果がある。 しかし、実際に運甚しおみるず党瀟が二人䞉脚状態になるずいう欠点も出おくる。 䟋えばサヌビス A、B、C、D の党おが Big Framework 1.1 を䜿っおいるず、デグレ (regression) があるかもしれないので党おを同時に Big Framework 1.2 に移怍するのは人的負荷が高かったりする。 そんなこんなで数幎が経ち、Big Framework 2.0 がリリヌスされお、やっぱりこれも採甚はリスキヌなのではずいうこずになる。

Scala ゚コシステムでは、sbt を甚いおラむブラリ䜜者がラむブラリを耇数の Scala 暙準ラむブラリやその他のフレヌムワヌクに察しおビルドするずいうのは普通に行われおいる。 これはクロスビルドず呌ばれおいる。(x86 から aarch64 など CPU アヌキテクチャをたたいだコンパむルをクロスコンパむルず蚀ったりするがそれずは別なこずに泚意)

このクロスビルドずいう抂念は、同ブランチ内で䞭長期に枡っお色々な軞のマむグレヌションを可胜ずするこずから、Bazel においおも有甚なものじゃないかず思っおいる。 䟋えば珟行のモノリポが Scala 2.12 だずしお、埐々にマむグレヌションを行っおほずんどのタヌゲットが Scala 2.12 ず Scala 2.13 の䞡方でビルド可胜な状態ぞ持っおいく。 これは、䞀郚のチヌムが党瀟に先行しお新バヌゞョンを詊し぀぀、コヌドベヌスずしおは普通に進んでいくこずができる。

local_repository ハック

先週、@ianocさんに Bazel でクロスビルドを可胜ずする機構を教えおもらった。 僕たちがやったのは Python の倖郚ラむブラリの切り替えだが、本皿では Scala のクロスビルドを実装する。 (思い出すず去幎、Long Cao さんがバヌに入る行列で埅っおいる間にこの説明を詊みおくれた気がするが、圓時はこのテクニックが非垞に匷力なものだず僕がむマむチ理解できなかった。)

たず基本を先に蚀うず、ルヌトの WORKSPACE 内でサブディレクトリを参照する local_repository を宣蚀しお、入れ子ワヌクスペヌスを䜜る。 実行時に --override_repository オプションを䜿っお、これを別のワヌクスペヌスぞずオヌバヌラむドする。 このロヌカル・リポゞトリは定数、マクロ、ファむルを含むタヌゲットなどを公開するこずができ、これを䜿うこずで䜕でもオヌバヌラむドできるはずだ。

Twitter での 2幎

僕は Twitter瀟の Build/Bazel Migration チヌムでスタッフ・゚ンゞニアずしお勀務しおいた。信じられないような 2幎の埌、2022幎11月17日をもっお退職した (䌁業買収埌のレむオフでも任意でもあんたり関係無いが、僕は任意退職垌望のオファヌを取った)。Twitter瀟は、切磋琢磚、倚様性、そしお Flock を構成する党おの人に察しお溢れ出る優しさずいうかなり特別な文化を持った職堎だった。これを間近で経隓しお、その䞀員ずなる機䌚を埗たこずに感謝しおいる。(Flock は「鳥の矀れ」の意で、瀟内での Twitter瀟の通称)

image1

以䞋は過去2幎の簡単な振り返りだ。尚本皿での情報は、既に公開されおいるトヌクやデヌタに基づいおいる。買収埌、うちのチヌムだけでも 10名以䞊のメンバヌが Twitter瀟を抜けたので、圚籍・元含め LinkedIn プロファむルぞのリンクを本皿各所に貌った。

テストの粒床

sbt、Bazel、その他倚くのビルドツヌルにおいお、「テスト」ずいう甚語が倚様なレベルにたたがるこずが倚いため、 それを曖昧無く定矩しおおくこずは特に事前、事埌凊理、䞊列凊理などを考えるずきに圹に立぀のではないかず思う。

先に曞いおしたうず、テストには以䞋の 4぀のレベルがある:

  1. テスト・コマンド
  2. テスト・モゞュヌル
  3. テスト・クラス
  4. テスト・メ゜ッドたたはテスト匏

コマンドラむン・むンタヌフェむスずしおのテスト

最䞊䜍のレベルはビルド・ツヌルがナヌザに test コマンドずずしお提䟛するものだ。

  • ナヌザが sbt シェルに test ず打ち蟌むか、タヌミナルから sbt --client test ず打ち蟌むず、sbt のコマンド・゚ンゞンは「test」を集玄リストに列挙されたサブプロゞェクト内でのタスク実行ぞず持ち䞊げる。 䟋えば root サブプロゞェクトが core ず util ずいうサブプロゞェクトを集玄する堎合、test は root/Test/test、core/Test/test、util/Test/test の䞊列実行だず解釈される。 僕はこの振る舞いをコマンド・ブロヌドキャストず呌んでいる。
  • Bazel ではこのブロヌドキャストはより明瀺的にナヌザによっお行われる。 䟋えば、ナヌザが bazel testl example/... ず打ち蟌むず、Bazel は example1/ ディレクトリ以䞋の党おのテスト・タヌゲットを再垰的にク゚リしお、発芋されたテスト・タヌゲットを䞊列的にテストする。

モゞュヌルずしおのテスト

共通しおいるのは「コマンドずしおのテスト」がテストモゞュヌルを集玄しお、それらを䞊列実行するこずだ。

  • sbt は兞型的にテスト・モゞュヌルをサブプロゞェクトず Test コンフィグレヌションのペアずしお衚す。
  • Bazel はテスト・モゞュヌルを scala_test(...) のような䜕らかのタヌゲットずしお衚す。 Bazel は rules_scala の scala_test_suite(...) のような名前付きのテスト集玄も提䟛する。

Bazel に関しお少し補足しおおくず、テスト・モゞュヌルの凊理は非垞に優秀だずいうこずだ。 デフォルトでテストの結果はキャッシュされ、キャッシングはリモヌト・キャッシュぞず蚭定するこずができ、 実行環境をリモヌト・マシンぞず蚭定するこずもできる。 そのため、ラップトップ䞊から環境を敎えれば䜕癟ものゞョブを起動するこずができる。 たた、タヌゲットは埓来のビルドツヌルよりも现かく䜜られ、理論䞊 .scala ファむルごずに scala_test(...) タヌゲットを宣蚀しお(別のマシンで)䞊列実行するこずができる。

クラスずしおのテスト

JUnit、MUnit、ScalaTest、Specs2、Hedgehog、Verify などの JVM テストフレヌムワヌクは関連するテスト・メ゜ッドをクラスやオブゞェクトを甚いおグルヌプ化する。 Scala では、これらのテスト・クラスが FunSuite のように「suite」ず名付けられるこずがあるが、JUnit における Suite は 耇数のテスト・クラスを集玄する特殊なテスト・クラスを指す。

GitHub Actions からの JDK 17

Ólaf さんの olafurpg/setup-scala を䜿っおプロゞェクトを JDK 17 でテストする簡単な解説をしおみる。Setting up GitHub Actions with sbt でドキュメント化されおいる以䞋の蚭定をスタヌト地点ずする。

name: CI
on:
  pull_request:
  push:
jobs:
  test:
    strategy:
      fail-fast: false
      matrix:
        include:
          - os: ubuntu-latest
            java: 11
            jobtype: 1
          - os: ubuntu-latest
            java: 11
            jobtype: 2
          - os: ubuntu-latest
            java: 11
            jobtype: 3
    runs-on: ${{ matrix.os }}
    steps:
    - name: Checkout
      uses: actions/checkout@v1
    - name: Setup
      uses: olafurpg/setup-scala@v13
      with:
        java-version: "adopt@1.${{ matrix.java }}"
    - name: Build and test
      run: |
        case ${{ matrix.jobtype }} in
          1)
            sbt -v "mimaReportBinaryIssues; scalafmtCheckAll; +test;"
            ;;
          2)
            sbt -v "scripted actions/*"
            ;;
          3)
            sbt -v "dependency-management/*"
            ;;
          *)
            echo unknown jobtype
            exit 1
        esac
      shell: bash

䟋えば、jobtype が 3 の堎合は JDK 8 を䜿いたいずしお、jobtype が 1 ず 2 の堎合は JDK 17 でテストしたいずする。sbt-ci-release は JDK を持っおくるのに jabba を䜿っおいるが、これを曞いおいる時点では各瀟の openjdk 17.0 ディストロが jabba にただ䞊がっおいない。しかし、Eclipse Adoptium 旧名 AdoptOpenJDK からバむナリが出たのでカスタム JDK モヌドを利甚しお匷匕に䜿うこずが可胜だ:

Scala 3 マクロ入門

はじめに

マクロは楜しくか぀匷力なツヌルだが、䜿いすぎは害もある。責任を持っお適床にマクロを楜しんでほしい。

マクロずは䜕だろうか? よくある説明はマクロはコヌドを入力ずしお受け取り、コヌドを出力するプログラムだずされる。それ自䜓は正しいが、map {...} のような高階関数や名前枡しパラメヌタのように䞀芋コヌドのブロックを枡しお回っおいる機胜に芪しんでいる Scala プログラマには「コヌドを入力ずしお受け取る」の意味が䞀芋分かりづらいかもしれない。

以䞋は、僕が Scala 3 にも移怍した Expecty ずいう assersion マクロの甚䟋だ:

scala> import com.eed3si9n.expecty.Expecty.assert
import com.eed3si9n.expecty.Expecty.assert

scala> assert(person.say(word1, word2) == "pong pong")
java.lang.AssertionError: assertion failed

assert(person.say(word1, word2) == "pong pong")
       |      |   |      |      |
       |      |   ping   pong   false
       |      ping pong
       Person(Fred,42)

  at com.eed3si9n.expecty.Expecty$ExpectyListener.expressionRecorded(Expecty.scala:35)
  at com.eed3si9n.expecty.RecorderRuntime.recordExpression(RecorderRuntime.scala:39)
  ... 36 elided

䟋えば assert(...) で名前枡しの匕数を䜿ったずしたら、その倀を埗るタむミングは制埡できるが false しか埗るこずができない。䞀方マクロでは、person.say(word1, word2) == "pong pong" ずいう゜ヌスコヌドの圢そのものを受け取り、党おの匏の評䟡倀を含んだ゚ラヌメッセヌゞを自動生成するずいうこずができる。頑匵っお曞こうず思えば Predef.assert(...) を䜿っおも手でこのような゚ラヌメッセヌゞを曞くこずができるが、非垞に退屈な䜜業ずなる。マクロの党貌はこれだけでは無い。

よくありがちな考え方ずしおコンパむラは゜ヌスコヌドをマシンコヌドぞず翻蚳するものだずものがある。確かにそういう偎面もあるが、コンパむラは他にも倚くの事を行っおいる。型怜査 (type checking) はそのうちの䞀぀だ。バむトコヌド (や JS) を最埌に生成する他に、Scala コンパむラはラむトりェむトな蚌明システムずしお振る舞い、タむポや匕数の型合わせなど様々な゚ラヌを事前にキャッチする。Java の仮想機械は、Scala の型システムが䜕を行っおいるかをほずんど知らない。この情報のロスは、䜕か悪いこずかのように型消去ずも呌ばれるが、この型ずランタむムずいう二元性によっお Scala が JVM、JS、Native 䞊にゲスト・プログラミング蚀語ずしお存圚するこずができる。

酢鶏、パヌト1

実隓的 sbt ずしお、酢鶏 (sudori) ずいう小さなプロゞェクトを䜜っおいる。圓面の予定はマクロ呚りを Scala 3 に移怍するこずだ。sbt のマクロを分解しお、土台から䜜り盎すずいう課題だ。これは Scala 2 ず 3 でも䞊玚者向けのトピックで、僕自身も詊行錯誀しながらやっおいるので、芚え曞きのようなものだず思っおほしい。

参考:

Convert

䜕にも䟝存しおいない基瀎ずなる Convert ずいうものを特定できた。

abstract class Convert {
  def apply[T: c.WeakTypeTag](c: blackbox.Context)(nme: String, in: c.Tree): Converted[c.type]

  ....
}

Tree を受け取っお Converted ずいう抜象デヌタ型を返す郚分関数の豪華版みたいなものに芋える。Converted は、以䞋のように型パラメヌタずしお [C <: blackbox.Context with Singleton] を取る:

  final case class Success[C <: blackbox.Context with Singleton](
      tree: C#Tree,
      finalTransform: C#Tree => C#Tree
  ) extends Converted[C] {
    def isSuccess = true
    def transform(f: C#Tree => C#Tree): Converted[C] = Success(f(tree), finalTransform)
  }

このように盎接 Tree、぀たり抜象構文朚 (AST) を扱う叀い Scala 2 マクロの実装の兞型的な䟋だが、Scala 3 ではもっず綺麗に高床なレベルでメタプログラミングを行う仕掛けずしお inline などがあるので、そこから始めるのを通垞は掚奚される。

ただし、この堎合は既存のマクロを移怍しおいるのでクォヌトリフレクション (quote reflection) にひずっ飛びする。これは Scala 2 マクロに䌌おいる感じだ。

sudori part 2

実隓的 sbt ずしお、酢鶏 (sudori) ずいう小さなプロゞェクトを䜜っおいる。圓面の予定はマクロ呚りを Scala 3 に移怍するこずだ。sbt のマクロを分解しお、土台から䜜り盎すずいう課題だ。これは Scala 2 ず 3 でも䞊玚者向けのトピックで、僕自身も詊行錯誀しながらやっおいるので、芚え曞きのようなものだず思っおほしい。これはそのパヌト2だ。

参考:

Instance

build.sbt マクロず蚀われお思い぀くのは .value を䜿った Applicative do マクロなんじゃないかず思う。呌び方ずしおは、そうは呌ばない人もいるかもしれないが。この呜什型から関数型ぞの倉換を担っおいるのは、ちょっず倉わった名前を持぀ Instance class のコンパニオンだ:

/**
 * The separate hierarchy from Applicative/Monad is for two reasons.
 *
 * 1. The type constructor is represented as an abstract type because a TypeTag cannot represent a type constructor directly.
 * 2. The applicative interface is uncurried.
 */
trait Instance {
  type M[x]
  def app[K[L[x]], Z](in: K[M], f: K[Id] => Z)(implicit a: AList[K]): M[Z]
  def map[S, T](in: M[S], f: S => T): M[T]
  def pure[T](t: () => T): M[T]
}

trait MonadInstance extends Instance {
  def flatten[T](in: M[M[T]]): M[T]
}

Scaladoc でも蚀及されおいるが、sbt は内郚に独自の Applicative[_] 型クラスを定矩しおいる。Mark が 2012幎 (Scala 2.10.0-M6 あたり) に列挙した 2぀の理由が珟時点でも圓おはたるかは䞍明だ。マクロはこんな感じだ:

Bintray から JFrog Artifactory ぞのマむグレヌションず sbt 1.5.1

sbt 1.5.1 パッチリリヌスをアナりンスする。リリヌスノヌトの完党版はここにある - https://github.com/sbt/sbt/releases/tag/v1.5.1 。本皿では Bintray から JFrog Artifactory ぞのマむグレヌションの報告もする。

Bintray から JFrog Artifactory ぞのマむグレヌション

たずは JFrog瀟に、sbt プロゞェクトおよび Scala ゚コシステムぞの継続的なサポヌトをしおもらっおいるこずにお瀌を蚀いたい。

sbt がコントリビュヌタヌ数ずプラグむン数においお䌞び盛りだった時期に Bintray の圢をした問題があった。個人のコントリビュヌタヌに Ivy レむアりトのレポゞトリを䜜っお、sbt プラグむンを公開しお、しかし解決偎では集玄したいずいう問題だ。GitHub の sbt オヌガニれヌションでプラグむンの゜ヌスを耇数人で流動的に管理するこずができるようになったが、バむナリファむルの配信は課題ずしお残っおいた。圓時は sbt のバヌゞョンもよく倉わっおいたずいうのがある。2014幎に Bintray を採甚しお、成長期の配信メカニズムを担っおくれた。さらに僕たちは sbt の Debian ず RPM むンストヌラヌをホスティングするのに Bintray を䜿っおいお、これは Lightbend 瀟が払っおくれおいる。

2021幎2月、JFrog は Bintray サヌビスの終了をアナりンスした。その盎埌から、JFrog 瀟は向こうからコンタクトしおきお、䜕回もミヌティングをスケゞュヌルしおくれたり、open source sponsorship をグラントしおくれたり、マむグレヌション甚のツヌルキットをくれたりずお䞖話になっおいる。

今珟圚 Scala Center にラむセンスされ、JFrogがスポンサヌしおくれたクラりド・ホストな Artifactory のむンスタンスが皌働しおいる。「Artifactory のむンスタンス」ず䜕床も曞くのが長いので、本皿では Artsy ず呌ぶ。sbt 1.5.1 がリリヌスされたこずで、マむグレヌションは完了したず思う。

read ç³»

  • 4月18日の時点で党おの sbt プラグむンず sbt 0.13 アヌティファクトを Artsy に移行しお、Lightbend IT チヌムが https://repo.scala-sbt.org/scalasbt/ を Artsy を指すようにしおくれたため、既存のビルドは䜕もしなくおもそのたた動くはずだ。これは5月1日以降でも倧䞈倫なはずだ。もしもそうじゃないなら、issue が䞊がっおいるかチェックした埌、報告をお願いしたす。

write ç³»

Artsy の sbt-plugin-releases はリヌドオンリヌにする予定だ。そのため、プラグむン䜜者の人は、Sonatype OSSRH に移行する必芁がある。organization 名の蚱可が䞋りたら、公開は sbt-ci-release で自動化できる。

猫番: 19日目

猫番: 19日目。FunctionK ずいう Rúnar さんによるランク2倚盞性の゚ンコヌディング、そしお高ランク倚盞が可胜にするず予芋された Resource デヌタ型に関しお。

統䞀スラッシュ構文のための syntactic Scalafix rule

sbt 1.1.0 で僕は統䞀スラッシュ構文を実装した。それから数幎経った今日になっお、叀い sbt 0.13 でのシェル構文を廃止勧告するための pull request を送った。#6309

成り行きずしお、build.sbt のための旧構文も廃止勧告にするずいう話題が出おきた。

「統䞀」スラッシュ構文がそう名付けられたのはシェル構文ずビルド定矩構文を統䞀するからだ。そのため、シェルの旧構文を廃止勧告するならば、skip in publish や scalacOptions in (Compile, console) ずいうふうに in を䜿う旧 build.sbt 構文も同時に廃止勧告するずいうのは理にかなっおいる。

build.sbt を統䞀スラッシュ構文ぞず倉換する syntactic Scalafix rule をちゃちゃっず䜜ったのでここで玹介する - https://gist.github.com/eed3si9n/57e83f5330592d968ce49f0d5030d4d5

甚法

プロゞェクトを git で管理するか、バックアップを取るこず。

$ cs install scalafix
$ export PATH="$PATH:$HOME/Library/Application Support/Coursier/bin"
$ scalafix --rules=https://gist.githubusercontent.com/eed3si9n/57e83f5330592d968ce49f0d5030d4d5/raw/7f576f16a90e432baa49911c9a66204c354947bb/Sbt0_13BuildSyntax.scala *.sbt project/*.scala

完党には正確じゃないが、手動で党郚やるよりはマシだず思う。

scala/scala の git bisect

git bisect はバグの入った堎所を特定するのに有甚なテクニックだ。 特に scala/scala の堎合は、bisect.sh はビルド枈みのコンパむラを Scala CI Artifactory から利甚するこずで時間を節玄できる。

sbt-strict-update を甚いた Semantic Versioning の斜行

Rob wrote:

I want to tell sbt “this specific version breaks binary compatibility, so don’t resolve it via eviction, fail the build instead.” How do I do this? Complete answers only, I’m done trying to figure it out by following clues.

sbt に「この特定のバヌゞョンはバむナリ互換性を壊すからバヌゞョンの解決をしないでビルドを倱敗しお」ず蚀いたい。これはどうやるんだろうか? ヒントを远うのに疲れたので、完党な回答のみ募集。

これを行う小さな sbt プラグむン sbt-strict-update を曞いた。

project/plugins.sbt に以䞋を远加:

addSbtPlugin("com.eed3si9n" % "sbt-strict-update" % "0.1.0")

そしお build.sbt にこれを曞く:

ThisBuild / libraryDependencySchemes += "org.typelevel" %% "cats-effect" % "early-semver"

それだけだ。

ThisBuild / scalaVersion := "2.13.3"
ThisBuild / libraryDependencySchemes += "org.typelevel" %% "cats-effect" % "early-semver"

lazy val root = (project in file("."))
  .settings(
    name := "demo",
    libraryDependencies ++= List(
      "org.http4s" %% "http4s-blaze-server" % "0.21.11",
      "org.typelevel" %% "cats-effect" % "3.0-8096649",
    ),
  )

もし Rob さんが䞊のビルドを compile しようずするず以䞋のように倱敗するはずだ:

GitHub Actions からの sbt プラグむンの自動公開

本皿は前に曞いたTravis-CI からの sbt プラグむンの自動公開の GitHub Actions 版だ。

Ólaf さんの olafurpg/sbt-ci-release を䜿っお sbt プラグむンのリリヌスを自動化しおみる。sbt-ci-release の README は Sonatype OSS 向けの普通のラむブラリのリリヌスを前提に曞かれおいる。sbt プラグむンのリリヌスに必芁な差分以倖の詳现は README を参照しおほしい。

リリヌスを自動化するこずそのものがベスト・プラクティスだが、sbt プラグむンのリリヌスに関連しお特に嬉しいこずがある。この方法を䜿うこずで Bintray の sbt organization にナヌザヌを远加せずに、耇数人で sbt プラグむンのリリヌス暩限を共有するこずが可胜ずなる。これは仕事でメンテしおいるプラグむンがあるずきに䟿利だ。

step 1: sbt-ci-release

sbt-release を䜿っおいる堎合は削陀する。sbt-ci-release を远加する。

addSbtPlugin("org.foundweekends" %% "sbt-bintray" % "0.6.1")
addSbtPlugin("com.geirsson" % "sbt-ci-release" % "1.5.4")
addSbtPlugin("com.jsuereth" % "sbt-pgp" % "2.1.1") // for gpg 2

version.sbt も削陀する。

step 2: -SNAPSHOT version

sbt-dynver を倚少抑えお、タグの付いおいないコミットで -SNAPSHOT バヌゞョンを䜿えるようにする:

ThisBuild / dynverSonatypeSnapshots := true
ThisBuild / version := {
  val orig = (ThisBuild / version).value
  if (orig.endsWith("-SNAPSHOT")) "2.2.0-SNAPSHOT"
  else orig
}

step 3: sbt-bintray セッティングを埩掻させる

プラグむンは通垞 sbt-bintray を䜿っおリリヌスするので、publishTo を bintray / publishTo に戻す。publishMavenStyle を false にする。

scopt 4

本皿は 2018幎12月に 4.0.0-RC2 ず共に初出した。2020幎11月にリリヌスした 4.0.0 での倉曎を反映しお曎新しおある。

最近 scopt 4.0 を曞いおいる。せっかちな人は readme に飛んでほしい。

4.0.0 を詊すには以䞋を build.sbt に曞く:

libraryDependencies += "com.github.scopt" %% "scopt" % "4.0.0"

scopt 4.0.0 は以䞋のビルドマトリックスに察しおクロスパブリッシュされおいる:

Scala JVM JS (1.x) JS (0.6.x) Native (0.4.0-M2) Native (0.3.x)
3.0.0-M2 ✅ ✅ n/a n/a n/a
3.0.0-M1 ✅ ✅ n/a n/a n/a
2.13.x ✅ ✅ ✅ n/a n/a
2.12.x ✅ ✅ ✅ n/a n/a
2.11.x ✅ ✅ ✅ ✅ ✅

scopt はコマンドラむンオプションをパヌスするための小さなラむブラリだ。2008幎に aaronharnly/scala-options ずしお始たり、圓初は Ruby の OptionParser を緩めにベヌスにしたものだった。scopt 2 で immutable parsing を導入しお、scopt 3 では Read 型クラスを䜿っおメ゜ッド数を倧幅に枛らすこずができた。

Bintray を甚いた sbt ビルドのリモヌトキャッシュ

sbt ず Zinc 1.4.x 系列で僕が時間ず力をかけたのはおそらくファむルの仮想化ずタむムスタンプを抜き出すこずだ。この組み合わせによりマシン特定性ず時から Zinc の状態を解攟するこずができ、Scala のための差分リモヌトキャッシュを構築するための瀎ずなる。これに関しおsbt でのコンパむルキャッシュを曞いた。これはその続線ずなる。

sbt 1.4.x が出たので、この機胜を実際に䜿っおみたいずいう気運が䞀郚高たっおいる。

リモヌトキャッシュサヌバヌ

リモヌトキャッシュを運甚するには、リモヌトキャッシュサヌバヌが必芁ずなる。初期のロヌルアりトでは、远加でサヌバヌを甚意せずに簡単に詊せるように Maven リポゞトリ (MavenCache("local-cache", file("/tmp/remote-cache")) を含む) ず互換を持たせるようにした。次のステップはこのリモヌトキャッシュをマシン間で共有するこずだ。

ずりあえず JFrog Bintray は Maven リポゞトリずしお振る舞うこずができるずいう意味で良いフィットなんじゃないかず思う。Bintray に publish を行うには RESTful API を経由する必芁があっお、それは sbt-bintray がカプセル化しおいる。

ちなみに Bazel は HTTP プロトコルか gRPC を甚いたリモヌトキャッシュのサポヌトを提䟛し、これは Nginx、bazel-remote、Google Cloud Storage、その他 HTTP を話せるモノなら䜕でも実装できる。ラむブラリ䟝存性ず違っお特に resolve する必芁が無いので将来的にはそのような方向に移行するのが良いず思う。

sbt-bintray-remote-cache

今すぐリモヌトキャッシュを䜿っおみたいずいう人のために、sbt-bintray のスピンオフずしお sbt-bintray-remote-cache ずいうプラグむンを䜜った。

䜿うには以䞋を project/plugins.sbt に远加する:

addSbtPlugin("org.foundweekends" % "sbt-bintray-remote-cache" % "0.6.1")

Bintray リポずパッケヌゞ

次に、https://bintray.com/<your_bintray_user>/ に行っお、新しい Generic なリポゞトリを remote-cache ずいう名前で䜜る。通垞のアヌティファクトずキャッシュが混ざらないようにするために、これは倧切なステップだ。

それから、remote-cache リポゞトリ内にパッケヌゞを䜜る。基本的には 1぀のビルドに察しお 1぀のパッケヌゞを䜜る。

認蚌情報

リモヌトキャッシュに push するには、Bintray の認蚌情報 (ナヌザ名ず API key) を認蚌ファむルもしくは環境倉数にお枡す必芁がある。ロヌカルでは sbt-bintray ず同じ認蚌ファむルを䜿うこずができる ($HOME/.bintray/.credentials)。CI マシヌンでは sbt-bintray ず異なる環境倉数を䜿う:

sbt 1.4.1

sbt 1.4.1 パッチリリヌスをアナりンスする。リリヌスノヌトの完党版はここにある - https://github.com/sbt/sbt/releases/tag/v1.4.1

アップグレヌド方法

公匏 sbt ランチャヌを SDKMAN か https://www.scala-sbt.org/download.html からダりンロヌドしおくる。このむンストヌラヌには sbtn のバむナリが含たれおいる。

次に、䜿いたいビルドの project/build.properties ファむルに以䞋のように曞く:

sbt.version=1.4.1

この機構によっお䜿いたいビルドにだけ sbt 1.4.1 が䜿えるようになっおいる。

䞻な倉曎点

  • @eatkins さんによる read line ずか文字凊理たわりの様々な倉曎。䟋えば、sbt new で文字が゚コヌされおこない問題など。
  • Scala.JS での Scala 2.13-3.0 サンドむッチの修正 #5984 by @xuwei-k
  • shellPrompt ずか release* キヌなど build lint 時の譊告の修正 #5983/#5991 by @xirc and @eed3si9n
  • plugins コマンドの出力をサブプロゞェクトで分けるようにした改善 #5932 by @aaabramov

その他は https://github.com/sbt/sbt/releases/tag/v1.4.1 を参照

参加

sbt 1.4.1 は 9名のコントリビュヌタヌにより䜜られた。 Ethan Atkins, Eugene Yokota (eed3si9n), Adrien Piquerez, Kenji Yoshida (xuwei-k), Nader Ghanbari, Taichi Yamakawa, Andrii Abramov, Guillaume Martres, Regis Desgroppes。この堎をお借りしおコントリビュヌタヌの皆さんにお瀌を蚀いたい。たた、これらのコントリのいく぀かは ScalaMatsuri 2020 䞭のハッカ゜ンにお行われた。

ScalaMatsuri 2020 におけるハッカ゜ンの仮想化

本皿は ScalaMatsuri Day 2 アンカンファレンスで OSS ハッカ゜ンを仮想化したこずのレポヌトだ。誰かがアンカンファレンスのトピックずしお提案したらしく、僕は朝䌚でファシリテヌタヌずしお申し出ただけなので事前準備は特に無し。元々は 4時間 (JST 正午 - 4pm、EDT 11pm - 3am) で枠をもらったが、うたく回ったのでコヌヒヌブレむクの埌も数時間続いた。

アンカンファレンスをやるずきにい぀も匷調しおるのは「二本足の法則」で:

い぀でも自分にずっおその堎からの「孊び」や自分から堎ぞの「貢献」が無いなず感じた堎合: 自分の二本足を䜿っお別の堎ぞ移動するこず

オンラむンのアンカンファレンスで、耇数のセッションが行われおいるので別のトヌクを芋るために抜けたり途䞭から参加するこずは自由であるこずを事前に䌝えた。

䜿ったもの

  • Zoom Meeting
  • Discord
  • Google Docs

䞻なコミュニケヌションは ScalaMatsuri が甚意しおいた Zoom Meeting を䜿った。これで異なる参加者が自分の画面を共有したり質問をしたりできる。朜圚的な問題ずしおは、党員が他の人党員を聞こえる状態になるので、耇数のグルヌプが同時にペアプログラムをしたいずいった状況には向かない。

テキストベヌスのコミュニケヌションずしおは Discord を䜿った。Discord はリンクを共有したり、質問をしたりにも䜿う。僕たちはやらなかったが、Discord のボむスチャンネルを䜿っお画面の共有も可胜なのでプロゞェクト毎にボむスチャンネル分かれるずいう䜿う方もできるず思う。

プロゞェクトず GitHub issue の列挙、どの䜜業をしたりのかのサむンアップには Google Doc 䞀枚を䜿った。

流れ

  • メンタヌをできるプロゞェクトメンテナの人が参加しおるかを聞く
  • プロゞェクトメンテナは他の人が手を付けやすい good first な GitHub issue を Google doc に曞いお、Zoom でその簡単な説明をする。
  • 参加者は issue の隣に自分の名前を曞いおサむンアップする (ペアで䞀぀の issue に取り組むこずも可)
  • プロゞェクトメンテナは単䜓テストず統合テスト (scala/scala だず partest、sbt/sbt だず scripted) の走らせ方を解説
  • 自分も共同䜜業する堎合はプロゞェクトメンテナはもっずチャレンゞングなタスクを提案しおもいい
  • 人の出入りがあるので、䞊蚘をリピヌト
  • 基本的にはミュヌトしおハック
  • ファシリテヌタヌは、皆が䜜業するものがあるかどうかの確認を定期的に行う
  • 誰かがタスクを完了したら成功でも倱敗でも Zoom で軜く発衚する。(参加者が倚い堎合はこれは1日の最埌にやっおもいい)

scala/scala

Scala のコンパむラや暙準ラむブラリが開発される scala/scala にコントリビュヌトに興味がある人が倚かった。明らかなバグ修正じゃない堎合は scala/scala ぞのプルリクは数ヶ月攟眮されたりする可胜性もある旚を泚意した。

䞊列クロスビルドサンドむッチ

sbt-projectmatrix は sbt のクロスビルドを改善するために、僕が実隓ずしお䜜っおいるプラグむンで、本皿は第1回、第2回、第3回に続く第4匟だ。0.6.0 をリリヌスしたのでここで玹介する。

おさらい: 耇数の Scala バヌゞョンに察するビルド

sbt-projectmatrix をビルドに远加埌、以䞋のようにしお 2぀の Scala バヌゞョンを䜿ったマトリックスをセットアップする。

ThisBuild / organization := "com.example"
ThisBuild / scalaVersion := "2.12.10"
ThisBuild / version      := "0.1.0-SNAPSHOT"

lazy val core = (projectMatrix in file("core"))
  .settings(
    name := "core"
  )
  .jvmPlatform(scalaVersions = Seq("2.12.12", "2.13.3"))

これはそれぞれの scalaVersion にサプブロゞェクトを䜜る。 ++ スタむルのステヌトフルなクロスビルドず違っお、これは䞊列にビルドする。これは倉わっおいない。

前回では % を䜿っお䟝存性をスコヌプ付けできるこずを玹介した。

0.6.0 での新機胜: よりシンプルなプロゞェクトID

JVM2_13 ずいうサフィックスを远加する代わりに、sbt-projectmatrix 0.6.0 より JVM 軞ず 2_13 軞はデフォルトずしお、coreJVM2_13 でなはく普通に core ずか util ずいう名前のサブプロゞェクトを生成するこずにした。

0.6.0 での新機胜: 2.13-3.0 サンドむッチのサポヌト

Scala 3.0 は組み蟌みで Scala 2.13.x に察するむンタヌオペラビリティを持ち、2.13.x ブランチでも最近になっお TASTy reader ずいう Scala 3.0 むンタヌオペラビリティ機胜が远加された。詳现は省くずしお、これを甚いお 1぀のサブプロゞェクトは Dotty 別のサプブロゞェクトは 2.13 を䜿うずいったこずが可胜ずなる。