ハイブリッド 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 オプションを使って、これを別のワークスペースへとオーバーライドする。 このローカル・リポジトリは定数、マクロ、ファイルを含むターゲットなどを公開することができ、これを使うことで何でもオーバーライドできるはずだ。Tree-sitter を用いた Scala 3 の高速パース

Twitter での 2年
僕は Twitter社の Build/Bazel Migration チームでスタッフ・エンジニアとして勤務していた。信じられないような 2年の後、2022年11月17日をもって退職した (企業買収後のレイオフでも任意でもあんまり関係無いが、僕は任意退職希望のオファーを取った)。Twitter社は、切磋琢磨、多様性、そして Flock を構成する全ての人に対して溢れ出る優しさというかなり特別な文化を持った職場だった。これを間近で経験して、その一員となる機会を得たことに感謝している。(Flock は「鳥の群れ」の意で、社内での Twitter社の通称)
以下は過去2年の簡単な振り返りだ。尚本稿での情報は、既に公開されているトークやデータに基づいている。買収後、うちのチームだけでも 10名以上のメンバーが Twitter社を抜けたので、在籍・元含め LinkedIn プロファイルへのリンクを本稿各所に貼った。
テストの粒度
sbt、Bazel、その他多くのビルドツールにおいて、「テスト」という用語が多様なレベルにまたがることが多いため、 それを曖昧無く定義しておくことは特に事前、事後処理、並列処理などを考えるときに役に立つのではないかと思う。 先に書いてしまうと、テストには以下の 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.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 でも上級者向けのトピックで、僕自身も試行錯誤しながらやっているので、覚え書きのようなものだと思ってほしい。 参考: Scala 3 Reference: Metaprogramming 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 などがあるので、そこから始めるのを通常は推奨される。sudori part 2
実験的 sbt として、酢鶏 (sudori) という小さなプロジェクトを作っている。当面の予定はマクロ周りを Scala 3 に移植することだ。sbt のマクロを分解して、土台から作り直すという課題だ。これは Scala 2 と 3 でも上級者向けのトピックで、僕自身も試行錯誤しながらやっているので、覚え書きのようなものだと思ってほしい。これはそのパート2だ。 参考: Scala 3 Reference: Metaprogramming 酢鶏、パート1 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.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.猫番: 19日目
猫番: 19日目。FunctionK という Rúnar さんによるランク2多相性のエンコーディング、そして高ランク多相が可能にすると予見された Resource データ型に関して。
統一スラッシュ構文のための syntactic Scalafix rule
sbt 1.1.0 で僕は統一スラッシュ構文を実装した。それから数年経った今日になって、古い sbt 0.13 でのシェル構文を廃止勧告するための pull request を送った。#6309 成り行きとして、build.sbt のための旧構文も廃止勧告にするという話題が出てきた。 will you also deprecate `scalacOptions in (Compile, console)` in *.sbt and *.scala files? I hope so — Seth Tisue (@SethTisue) February 16, 2021 「統一」スラッシュ構文がそう名付けられたのはシェル構文とビルド定義構文を統一するからだ。そのため、シェルの旧構文を廃止勧告するならば、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 *.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.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).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つのパッケージを作る。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 へのプルリクは数ヶ月放置されたりする可能性もある旨を注意した。自由、平等、ボックス化されたプリミティブ型
ScalaMatsuri 2020 で ‘自由、平等、ボックス化されたプリミティブ型’ というトークで登壇しました。
並列クロスビルドサンドイッチ
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.Twitter に入社しました
本日付けで Twitter の Build Team に入社しました。世界中にいる Twitter 社のデベロッパーをサポートする次世代ビルド・システムの構築に関わることになります。 このチームはモノリポ・ビルドツールである Pants の開発に関わっていて、社内のシステムを Bazel へ移行させるのが当面の責務となると思います。デベロッパー・エクスペリエンスや開発効率ということに関して熱い思いを持っているチームと一緒に働けるという、僕が願っていた仕事なので、チームの人たちや新しい課題との出会いを楽しみにしています。 また、この場を借りて過渡期に DM などで、大丈夫にしてるかとか、社内で僕のことを推薦してくれたり、プロジェクトのオファーなど色々声をかけてくれた皆さんに感謝したいです。そんな声があったので元気にやってこれました。ありがとうございます。4月に義務サバティカルが始まってから、これまで時間が無くてできなかったビルドキャッシュとか Selective functor みたいな作業をしたり、Scala Center の素晴らしい方々とコラボすることができたので、そういう意味では色々良かったなと思います。 EE Build team は「San Francisco, Remote US」というロケーションからまだ募集中みたいなので、興味のある人は応募して一緒に作業しましょう。Travis-CI からの sbt プラグインの自動公開
本稿では Ólafur さんの 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.5.6") addSbtPlugin("com.geirsson" % "sbt-ci-release" % "1.5.3") 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 にする。Defx: Neovim のためのファイル・エクスプローラー・プラグイン

sbt 1.3.12
sbt 1.3.12 パッチリリースをアナウンスする。リリースノートの完全版はここにある - https://github.com/sbt/sbt/releases/tag/v1.3.12 。 特に Scala Center にお礼を言いたい。バグ報告、pull request レビュー、コントリビューションがちゃんと正しい所に行くかなどメンテ活動を行うにはある程度時間がかかるが、5月中の sbt のメンテ活動は Scala Center がスポンサーしてくれた。Daryja さん始め Scala Center のメンバーは皆気軽に共同作業しやすい人たちだ。 sbt 1.3.11 からの変更点 sbt 1.3.11 で launcher 統合周りにリグレッションがあり、repositories ファイルが無視されるという形のバグが出た。sbt 1.3.12 はそれを修正する。 #5583 アップグレード方法 通常は project/build.properties を sbt.version=1.3.12 と書き換えるだけで ok だ。しかし、リリースにスクリプトの修正が含まれている場合もあり、また全ての JAR ファイルが予め入った *.(zip|tgz|msi) を使ったほうが初回の依存性解決が速くなるためインストーラーを使ったインストールを推奨する。インストーラーは SDKMAN などに公開される。 sdk upgrade sbt Homebrew に関する注意 Homebrew のメンテナはもっと brew 依存性を使いたいという理由で JDK 13 への依存性を追加した brew#50649。そのため、PATH が通っている java が JDK 8 や 11 であっても sbt が JDK 13 で実行されるようになってしまう。sbt 1.3.11
sbt 1.3.11 パッチリリースをアナウンスする。リリースノートの完全版はここにある - https://github.com/sbt/sbt/releases/tag/v1.3.11 。 特に Scala Center にお礼を言いたい。バグ報告、pull request レビュー、コントリビューションがちゃんと正しい所に行くかなどメンテ活動を行うにはある程度時間がかかるが、5月中の sbt のメンテ活動は Scala Center がスポンサーしてくれた。Daryja さん始め Scala Center のメンバーは皆気軽に共同作業しやすい人たちだ。 アップグレード方法 通常は project/build.properties を sbt.version=1.3.11 と書き換えるだけで ok だ。しかし、リリースにスクリプトの修正が含まれている場合もあり、また全ての JAR ファイルが予め入った *.(zip|tgz|msi) を使ったほうが初回の依存性解決が速くなるためインストーラーを使ったインストールを推奨する。インストーラーは SDKMAN などに公開される。 sdk upgrade sbt Homebrew に関する注意 Homebrew のメンテナはもっと brew 依存性を使いたいという理由で JDK 13 への依存性を追加した brew#50649。そのため、PATH が通っている java が JDK 8 や 11 であっても sbt が JDK 13 で実行されるようになってしまう。 sbt が JDK 13 で実行するのを回避するには jEnv をインストールするか、SDKMAN に乗り換える必要がある。 主な変更点 sbt 1.Jar Jar Abrams
Jar Jar Abrams は、Java ライブラリをシェーディングするユーティリティである Jar Jar Links の実験的 Scala 拡張だ。 ライブラリ作者にとって他のライブラリは諸刃の剣だ。他のライブラリを使うことは作業の二重化を避け、他のライブラリを使いたくないというのはダブルスタンダードと言われかねない。しかし、その一方で、ライブラリを追加する度にそれはユーザ側にすると間接的依存性が追加されたことになり、衝突が起こる可能性も上がることになる。これは単一のプログラム内において 1つのバージョンのライブラリしか持てないことにもよる。 このような衝突はプログラムがランタイムやフレームワーク上で実行される場合によく起こる。sbt プラグインがその例だ。Spark もそう。1つの緩和策として間接的ライブラリを自分のパッケージの中にシェーディングするという方法がある。2004年に herbyderby (Chris Nokleberg) さんは Jar Jar Links というライブラリを再パッケージ化するツールを作った。 2015年に Wu Xiang さんが Jar Jar Links を使ったシェーディングのサポートを sbt-assembly に追加した。これは前向きな一歩だったが、課題も残っていた。問題の 1つは Scala コンパイラは ScalaSignature 情報を *.class ファイルに埋め込むが、Jar Jar がそのことを知らないことだ。2020年になって Simacan社の Jeroen ter Voorde さんが ScalaSignature の変換を sbt-assembly#393 にて実装した。sbt 以外でもこれは役に立つかもしれないので、独立したライブラリに抜き出した。これが Jar Jar Abrams だ。 core API コアには shadeDirectory 関数を実装する Shader オブジェクトがある。 package com.eed3si9n.jarjarabrams object Shader { def shadeDirectory( rules: Seq[ShadeRule], dir: Path, mappings: Seq[(Path, String)], verbose: Boolean ): Unit = .sbt での Selective ファンクター
sbt コア・コンセプトのトークをするとき僕は sbt をカジュアルに関数型なビルド・ツールと言っている。関数型プログラミングの 2つの特徴としてデータを変化させるのではなく immutable (不変)なデータ構造を使うことと、いつ、どのようにして effect (作用) を取り扱うかに気を使っていることが挙げられる。 セッティングとタスク その観点から見ると、セッティング式とタスクはその 2点に合致していると考えることができる: セッティング列はビルドの不変グラフを形成する。 タスクは作用を表す。 匿名セッティングは Initialize[A] で表され、以下のようになっている: sealed trait Initialize[A] { def dependencies: Seq[ScopedKey[_]] def evaluate(build: BuildStructure): A // approx .... } 名前の付いたセッティングは Setting クラスで表される: sealed class Setting[A] private[Init] ( val key: ScopedKey[A], val init: Initialize[A], val pos: SourcePosition ) .... sbt.Task は副作用関数 () => A のラッパーだと便宜的に考えていい。ただし、僕たちが「compile はタスクだ」と言うとき、の文脈でのタスクは Initialize[Task[A]] で表される。つまり、これは Task[A] 型を返すセッティングだ。 これは Def.task の戻り型 Def.Initialize[Task[A]] を見ることで確認することができる。 Applicative 合成 Def.sbt で約束 (promise) を守る
build.sbt は、自動的な並列処理を行うタスク・グラフを定義するための DSL だ。タスク同士のメッセージ・パッシングは something.value マクロで表され、これは Applicative 合成 (task1, task2) mapN { case (t1, t2) => .... } をエンコードする。 長く走っている task1 があるとき、途中で task2 と通信できる仕組みがあればいいと思っていた。 通常は task1 をサブタスクに分けることでこれを解決する。しかし、それを実装するのは一筋縄ではいかないこともある。例えば、Zinc に半分だけコンパイルして、残りは後で続けて下さい? もしくは Coursier に解決だけ行って実際のダウンロードは後でとどう言えばいいだろうか? たたき台として task1 が何らかの JSON ファイルを生成して、task2 はファイルが現れるまで待って、それを読み込むというやり方が考えられる。JSON ファイルの代わりに Promise[A] のような並行データ構造を使って改善することができる。しかし、待機という厄介なものが残っている。sbt は並列に実行するタスクの数を限っているので、待機のために枠を使うのはもったいない。Daniel さんの Thread Pools にこの辺りの事が良くまとまっている。今回あるのは差し当たり作業を一切行わないブロッキング IO ポーリングと考えることができると思う。 Def.promise scala.concurrent.Promise のラッパーを実装して Def.promise と呼んだ。具体例で説明する: val midpoint = taskKey[PromiseWrap[Int]]("") val longRunning = taskKey[Unit]("") val task2 = taskKey[Unit]("don't call this from shell") val joinTwo = taskKey[Unit]("") // Global / concurrentRestrictions := Seq(Tags.sbt でのコンパイルキャッシュ
Google のビルドインフラ Blaze (現在は Bazel としてオープンソース化されている) のことを知ってから Scala のツールチェインにも似たような仕組みが欲しいとずっと思い続けてきた。これは特に独創的な発想という訳では無く、Peter Vlugter さんと Ben Dougherty さんの nailgun Zinc での機能 (Pants で使われていた?) や、Krzysztof Romanowski さんの Hoarder など先行研究もある。それらは、作業ディレクトリに合わせて Zinc Analsis ファイル内に格納されている絶対パスを変換するというアイディアから成り立っている。 僕の作業の詳細に入る前に、問題スペースをざっとデモしよう。 ビルドのマシン依存性 Akka の akka-actor/compile を sbt 1.3.10 でビルドするとこのようになる: cd ~/work/quicktest/ git clone git@github.com:akka/akka.git akka-0 cd akka-0 sbt akka > akka-actor/compile [info] Generating 'Tuples.scala' [info] Generating 'Functions.scala' [info] Updating [info] Resolved dependencies [info] Updating [info] Formatting 22 Java sources... [info] Reformatted 0 Java sources [info] Compiling 191 Scala sources and 28 Java sources to /Users/eed3si9n/work/quicktest/akka-0/akka-actor/target/scala-2.Zinc 1.4.0-M1
Zinc 1.4.0-M1 をリリースした。これはベータ版であって将来の 1.4.x との互換性は保証されないことに注意してほしい。ただ、1.3.x と比較的近いコミットを選んだので実用性は高いはずだ。 Zinc を Scala 2.12 と 2.13 へとクロスビルドした zinc#754 by @eed3si9n ScalaPB を 0.9.3 へとアップグレードした zinc#713 by @slandelle ZipUtils 内での java.util.Date の使用を java.time 系へと置き換えた zinc#714 by @slandelle Zinc は Scala のための差分コンパイラだ。Zinc は Scala 2.10 ~ 2.13 と Dotty をコンパイルすることが可能だが、これまでの所 Zinc そのものは Scala 2.12 で実装されてきた。これは Scala 2.12 で実装されている sbt 1.x としては問題無いが、Zinc を 2.13 でもクロスビルドして欲しいという要望は前からあった。 どうやら Gatling は Zinc をライブラリとして使っているらしく、Gatling のコア開発者の Stephane Landelle さんはアップデートに必要なパッチを送ってくれた。最後に僕がする必要があった作業は入り組んだサブプロジェクトを解きほぐして再配線することだが、それには僕が昨日書いた sbt-projectmatrix を使った。 Li Haoyi さんも Mill を Scala 2.並列クロスビルド、パート3
sbt-projectmatrix は sbt のクロスビルドを改善するために、僕が実験として作っているプラグインで、本稿は前々回、前回に続く第3弾だ。0.5.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.10", "2.11.12")) これは coreJVM2_11 と coreJVM2_12 というサブプロジェクトを作る。 ++ スタイルのステートフルなクロスビルドと違って、これは並列にビルドする。これは変わっていない。 前回では列で複数の次元を表現できる VirtualAxis を紹介した。 0.5.0 での新機能 0.4.0 は結構いい線いっていたが、実際に使ってみると不便な点があった。まずは % 構文が無いことだ。 サブプロジェクト間で Test コンフィギュレーションからだけ依存したり、Compile 同士、Test 同士で依存するというのは良くあることだ。0.5.0 は % を追加してこれを可能とする。 lazy val app = (projectMatrix in file("app")) .Lightbend での6年
2014年3月に Lightbend社 (当時 Typesafe社) に入社した。信じられないような 6年の後、2020年4月7日をもって退職となった。Lightbend、パートナー各社、顧客、そしてカンファレンスなどで出会った色んな人とつながりを持ったり一緒に作業する機会をもらえたのは感謝している。振り返ると COVID-19前の時代でヨーロッパ、アジア、北米などを数ヶ月ごとに飛び回ってカンファレンスに出たり社内合宿を行っていたのが現実離れして感じる。 以下は過去6年の簡単な振り返りだ。 2014 Scala を趣味で始めたのは 2009年の終わり頃なので、2014年の時点では 4年ぐらいは書いていたのではないか。丁度「独習 Scalaz」が終わって、関連するネタで最初の nescala のトークを行った。10個ぐらいの sbt プラグインを作って、Stackoverflow でも良く活動してた。 3月に Lightbend社のツーリングチーム (当時は Typesafe社「Q課」) に入社した。当時のメンバーは Josh Sereth と Toni Cunei。Josh と sbt のメンテをするのは確かに仕事の分担だけども、仕事は戦略もしくは、難関というか、学びの多い顧客ドリブンなものが大半だった。入社した直後に顧客先に国内線で飛んで、Apache Ivy のコードを読んだりプロファイリングしたりしたのを覚えている。最初は面食らったが、すぐに sbt の中ではライブラリ依存性周りが最も慣れようになった。 2014年5月には sbt のバージョン番号を 0.13.2 から 0.13.5 と飛ばして sbt 1.x シリーズのテクノロジーレビューとした。必要な機能を実験的に導入していくことで sbt 1.x との差が大きくなり過ぎないようにするというアイディアだった。 sbt 0.13.6 になって、未解決の依存性のエラーを足りない依存性の木で表示したり、eviction warning、updateOptions での withLatestSnapshots など僕が追加したライブラリ依存性周りの機能が出てくるようになる。 2014年後半には Q課は Typesafe Reactive Platform v1 のためのインフラ作りを行った。これは Toni が実装した Dbuild を元にした商用配布パッケージだ。 2015 2015年3月、Josh と一緒に僕の最初の Scala Days のトーク ‘The road to sbt 1.ユーザランドでの警告とエラー、パート2
先週は、Scala でユーザランドから警告を出す仕組みの提案である #8820 について書いた。例として ApiMayChange アノテーションを実装した。 package foo import scala.annotation.apiStatus, apiStatus._ @apiStatus( "should DSL is incubating, and future compatibility is not guaranteed", category = Category.ApiMayChange, since = "foo-lib 1.0", defaultAction = Action.Warning, ) implicit class ShouldDSL(s: String) { def should(o: String): Unit = () } これは始めとしては一応使えるけども、少し冗長だ。もしなんらかの API ステータスが頻繁に使われる場合、ライブラリ作者が独自のステータスアノテーションを定義できると嬉しいと思う。今日はその方法を考える。 その前に少し裏方の解説を必要とする。コンパイラがアノテーションを見る時この情報は AnnotationInfo として渡され、引数は構文木で表される。これによってコールサイトのソースコードはあるが、アノテーションのコードがコンストラクタで何かやったなどの事は分からない。一方、アノテーションクラスにタグ付けされたアノテーションのことは分かる。 ApiMayChange の実装再び アノテーションのに付けることを前提に作られたアノテーションはメタアノテーションと呼ばれ、これを使うことで apiStatus の継承を行うことができる: import scala.annotation.{ apiStatus, apiStatusCategory, apiStatusDefaultAction } import scala.annotation.meta._ @apiStatusCategory("api-may-change") @apiStatusDefaultAction(apiStatus.Action.Warning) @companionClass @companionMethod final class apiMayChange( message: String, since: String = "", ) extends apiStatus(message, since = since) category や defaultAction を extends apiStatus(.Scala におけるユーザランドでのコンパイラ警告
一ライブラリ作者として、Scala でメソッドをタグ付けしてカスタムのコンパイラ警告やエラーを発動できるといいなと前から思っている。何故意図的にコンパイラエラーを出す必要があるのかと思うかもしれない。一つのユースケースとしては、API を廃止した後でマイグレーションのためのメッセージを表示させることだ。 Restligeist macro: n. A macro that fails immediately to display migration message after implementation has been removed from the API. — ∃ugene yokot∀ (@eed3si9n) August 30, 2016 僕はこれを Restligeist macro、つまり地縛霊マクロと呼んでいる。例えば、sbt 1.3.8 において <<= を使うと以下のエラーメッセージが起動時に表示される。 /tmp/hello/build.sbt:13: error: `<<=` operator is removed. Use `key := { x.value }` or `key ~= (old => { newValue })`. See http://www.scala-sbt.org/1.x/docs/Migrating-from-sbt-013x.html foo <<= test, ^ [error] sbt.compiler.EvalException: Type error in expression [error] Use 'last' for the full log.Giter8 0.12.0
giter8.version
Giter8 0.12.0 に giter8-launcher という小さなアプリを追加した。このアプリの目的は Giter8 テンプレートの振る舞いを予測可能にすることにある。現状だと、テンプレート作者が Giter8 バージョン X を想定してテンプレートを作ったとしてもユーザー側は “sbt new” に同梱される別な Giter8 バージョン Y を使って実行されている。
sbt の良いアイディアの一つにユーザーがどのバージョンの sbt
スクリプトをインストールしていてもコアの sbt バージョンはビルド作者が project/build.properties
ファイルを使って指定できるというものがある。これによって「自分のマシンでしか動作しない」問題が大幅に改善される。giter8-launcher は sbt における sbt-launcher に同様のものだ。giter8-launcher はテンプレートのクローンして、project/build.properties
ファイルを読み込んで、テンプレートのレンダリングに用いる実際の Giter8 バージョンを決定する。
テンプレート作者は project/build.properties
ファイルを用いて以下のように Giter8 バージョンを指定できる:
giter8.version=0.12.0
VirtualAxis を用いた並列クロスビルド
sbt-projectmatrix は sbt のクロスビルドを改善するために、僕が実験として作っているプラグインで、本稿は前篇に続く第2弾だ。0.4.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.10", "2.11.12")) これは coreJVM2_11 と coreJVM2_12 というサブプロジェクトを作る。 ++ スタイルのステートフルなクロスビルドと違って、これは並列にビルドする。これは変わっていない。 前篇ではこの考え方をクロス・プラットフォームやクロス・ライブラリへと応用させることを考えた。 0.2.0 の問題 Support for mixed-style matrix dependencies #13 と Support for pure Java subprojects #14 という 2つの issue が立てられて、0.Pamflet 0.8.2
Pamflet は短い文書、特にオープンソース・ソフトウェアの ユーザ・ドキュメントを公開するためのアプリだ。
Pamflet 0.8.2 はモノスペースのタイプフェイスを SFMono へと変更する。また、Blueprint から Bootstrap に移行したときに不意に導入されたピンクの文字色を元に戻す。

依存性解決のセマンティクス
依存性リゾルバー 依存性リゾルバー (dependency resolver)、もしくはパッケージマネージャーは、ユーザーによって与えられた制約の集合を元に矛盾しないモジュールの集合を決定するプログラムだ。通常この制約要件はモジュール名とそれらのバージョン番号を含む。JVM エコシステムにおける Maven モジュールは organization (group id) も指定に用いられる。その他の制約として、バージョン範囲、除外モジュール、バージョンオーバーライドなどもある。 パッケージングは大まかに OS パッケージ (Homebrew、Debian packages など)、特定のプログラミング言語のモジュール (CPAN、RubyGem、Maven など)、特定のアプリケーションのためのエクステンション (Eclipse プラグイン、IntelliJ プラグイン、VS Code extensions など) の 3つのカテゴリーがある。 依存性解決のセマンティクス 考え始めの近似としてモジュール依存性を DAG (有向非巡回グラフ) だと考えることができる。これは依存性グラフ、もしくは “deps graph” と呼ばれる。以下のような 2つのモジュール依存性があるとする: a:1.0。これはさらに c:1.0 に依存する。 b:1.0。これはさらに c:1.0 と d:1.0 に依存する。 +-----+ +-----+ |a:1.0| |b:1.0| +--+--+ +--+--+ | | +<-------+ | | v v +--+--+ +--+--+ |c:1.0| |d:1.0| +-----+ +-----+ a:1.0 と b:1.0 に依存すると、a:1.0、b:1.0、c:1.0、そして d:1.0 が得られる。これは木を歩いているだけだ。 間接依存性にバージョン範囲を含むと状況はもう少し複雑になる。sbt 1.3.0
皆さんこんにちは。sbt プロジェクトを代表して sbt 1.3.0-RC1 をアナウンスします。これは sbt 1 のフィーチャーリリース第3弾で、バイナリ互換性は維持しつつ新機能にフォーカスを当てたリリースとなっている。sbt 1 は Semantic Versioning にもとづいてリリースされるので、プラグインは sbt 1.x シリーズ中機能することが期待されている。 2019年3月29日までに大きな問題が見つからなければ、1.3.0-RC1 は 1.3.0 final 版となる予定だ。 sbt 1.3 の主な新機能はデフォルトでの Coursier を使ったライブラリ管理、ClassLoader レイヤリング、IO の改善、そして super shell だ。これらの機能の組み合わせがビルドのユーザーエクスペリエンスを向上することを願っている。 互換性に影響のある変更点 Coursier を用いたライブラリ管理。詳細は後ほど。 ClassLoader レイヤリング。詳細は後ほど。 super shell。詳細は後ほど。 マルチコマンドの先頭にセミコロンが要らなくなった。clean;Test/compile; で動作するようになった。 #4456 by @eatkins sbt.internal.inc.ZincUtil 以下の関数で LM を使うものが ZincLmUtil に移動して、Zinc から LM に依存しないようになった。 zinc#655 by @dwijnand Coursier を用いたライブラリ管理 sbt 1.3.0 はライブラリ管理に Coursier を採用する。Coursier は、ライブラリ依存解決を行うもので Ivy に似ているが、より高速化を求めて Alexandre Archambault さん (@alexarchambault) により一から Scala でリライトされたものだ。sbt-projectmatrix を用いた並列クロスビルド
去年 sbt のクロスビルドを改善するために、sbt-projectmatrix という実験的プラグインを書いた。0.2.0 をリリースしたのでここで紹介する。 複数の Scala バージョンに対するビルド sbt-projectmatrix をビルドに追加後、以下のようにして 2つの Scala バージョンを使ったマトリックスをセットアップする。 ThisBuild / organization := "com.example" ThisBuild / scalaVersion := "2.12.8" ThisBuild / version := "0.1.0-SNAPSHOT" lazy val core = (projectMatrix in file("core")) .settings( name := "core" ) .jvmPlatform(scalaVersions = Seq("2.12.8", "2.11.12")) これは coreJVM2_11 と coreJVM2_12 というサブプロジェクトを作る。 ++ スタイルのステートフルなクロスビルドと違って、これは並列にビルドする。 2つのマトリックス 1つ以上のマトリックスがあると面白くなる。 ThisBuild / organization := "com.example" ThisBuild / scalaVersion := "2.12.8" ThisBuild / version := "0.1.0-SNAPSHOT" // uncomment if you want root // lazy val root = (project in file(".git リポジトリの分岐
サブディレクトリを新しいリポジトリへ分岐させる (シンプルな場合) git clone --no-hardlinks --branch master originalRepoURL childRepo cd childRepo git filter-branch --prune-empty --subdirectory-filter path/to/keep master git remote remove origin git prune git gc --aggressive originalRepoURL、master、path/to/keep などは適当な値に変える。全てのブランチを処理したい場合は -- --all を使う。 サブディレクトリを新しいリポジトリへ分岐させる (複雑な場合) 複数のパスをフィルターしたい場合は、--index-filter と brew install gnu-sed findutils によってインストールできる GNU xargs と GNU sed を使う必要がある。 git clone --no-hardlinks --branch master originalRepoURL childRepo cd childRepo git filter-branch --index-filter 'git rm --cached -qr --ignore-unmatch -- . && git reset -q $GIT_COMMIT -- path1/to/keep path2/to/keep' --prune-empty master git filter-branch --prune-empty --parent-filter 'gsed "s/-p //g" | gxargs git show-branch --independent | gsed "s/\</-p /g"' git remote remove origin git prune git gc --aggressive originalRepoURL、master、path1/to/keep、path2/to/keep などは適当な値に変える。全てのブランチを処理したい場合は -- --all を使う。君達の JDK は全て SDKMAN! がいただいた
これは Travis CI に自分で JDK をインストールする解説の第2弾だ。以前は、jabba を紹介した。 今日は SDKMAN!, という、Marco Vermeulen (@marc0der) さんが作った元気な名前のツールを見ていく。これは、JDK の他にも Groovy、Spark、sbt など JVM 上の様々なツールを対象とする環境マネージャーだ。 AdoptOpenJDK 11 と 8 2020-09-23 更新: バージョン番号の正規表現を更新した。 2019-11-06 更新: SDKMAN の更新プロンプトが CI をブロックするのを回避するために sdkman_auto_selfupdate を追加した。また、sdk install の行に || true を追加した。 2019-07-08 更新: パッチバージョンを自動検知するように変更した。古い版は GitHub に置いてある。 以下は SDKMAN! を使って Travis CI 上で AdoptOpenJDK 8 と 11 を用いてクロスビルドする方法だ: dist: xenial language: scala scala: 2.12.10 matrix: include: - env: - ADOPTOPENJDK=11 - env: - ADOPTOPENJDK=8 before_install: # adding $HOME/.Docker での sbt
Docker 内で sbt を走らせたかったので、イメージをいくつか作った。GitHub リポジトリは eed3si9n/docker-sbt。
Pamflet 0.8.0
年末の連休中に Pamflet の left TOC (目次) を実装して、Pamflet 0.8.0 としてリリースした。

Pamflet は短い文書、特にオープンソース・ソフトウェアの ユーザ・ドキュメントを公開するためのアプリだ。
scala.Seq のマスキング
現行の Scala 2.13.0-M5 のままで行くと、scala.Seq は scala.collection.Seq から scala.collection.immutable.Seq に変更される予定だ。Scala 2.13 collections rework に何故今まで不変じゃなかったのかの解説が少し書かれている。行間から推し量ると、scala.Seq がデフォルトで不変になることを喜ぶべきだと言っているんだと思う。 デフォルトで列が不変になることはアプリや新しく書かれるコードには良いことだと思う。ライブラリ作者にとってはもう少しこみいっているかもしれない。 あなたがクロスビルドされたライブラリを持っていて ライブラリのユーザも複数の Scala バージョンを使っていて ライブラリのユーザが Array(...) を使っていた場合 この不変 Seq への変更は、breaking change つまり非互換な API 変更となりうる。 失敗例としては scopt/scopt#218 がある。僕が scopt のクロスビルドを行ったが、args を渡せなくなったらしい。Scala 2.13.0-M5 においても args は Array[String] のままだ。 シンプルな修正は全てのソースにおいて scala.collection.Seq を import することだ。僕が欲しいのは Seq を使うとコンパイルが通らなくなることだ。 scala.Seq を unimport する まず最初にやってみたのは scala.Seq を unimport して、scala.collection.Seq か scala.collection.immutable.Seq のどちらかを import することを強制することだ。 import scala.{ Seq => _, _ } 最も外側にあるスコープ内でデフォルトの import scala.カンファレンスを女性にとってよりセーフなスペースにするための方法
技術カンファレンスにおける女性の参加率 (やその他のバックグラウンドを持つ人の参加率) を改善するには、周辺のカルチャーを変えていく必要がある。そのためには以下の 2点に関してハッキリとしたシグナル化とコミュニケーションを必要とする
- カンファレンスで女性参加者をナンパするのはダメ
- 技術的な能力を前提として、女性参加者とプロフェッショナルかつ対等に接する これらは全てのカンファレンスにおいて基調講演の前と、社交タイムの前に繰り返し連絡されるべき事項だ。
sbt のための super shell
週末中に sbt のための super shell の実装がまとまってきたのでここに報告する。大まかな概要としては、ターミナル画面の下 n行を乗っ取って今走っているタスクを表示させる。 ログを現状報告に使うことの限界 ログは多くの場面で有用で、時としては何が起こっているかを知るための唯一の現実解であったりする。だけども、sbt のようなコンソールアプリにおいては、ログを使ってビルド・ユーザに現在なにが起こっているかを報告するのはうまくいかないことがある。 仮に sbt が一切ログを表示しなかったとすると、sbt が長時間走るタスクを実行して一見固まってしまったときに何が起きているか分からなくなる。そのため、update のようなタスクは “Updating blabla subproject” と “Done updating” といった開始、終了ログを表示する。update タスクはユーザやビルドによって非常に長い時間がかかってしまうことで有名だが、少ないライブラリ依存性を持つその他の多くのビルドは 1s 以内で完了する。そのような場合、ビルドの開始時に “Done updating” がズラーッと壁のように並ぶことになる。 つまり、ログ表示を現状報告に使うのはログが出すぎてうるさい状態と、情報が足りなくて不便な両極端の間を揺れることになる。 show your work (途中式を書くこと) 人生における多くの事と同様に、やったことの提示方法やユーザー・インターフェイスはその作業とかプロダクトそのものの必要不可欠な側面であり、特にその作業やプロダクトが自明で無いものほどそれが顕著になる。 僕は、sbt が単一のコマンド実行内においてタスクを並列処理することを当たり前のように考えてきた。しかし、最近になってその事を知らない人がいる場面に出くわすことが増えてきた。これは、実はもっともなことだ。なぜなら、ビルドの DSL もユーザインターフェイスも sbt がタスクの並列処理を行っていることを明らかにしていないからだ。 さらに、古参のユーザが sbt がタスクを並列実行していることを信じていたとしても、現在はどのタスクがパフォーマンスのボトルネックになっているのかを知るのが難しい。何らかのプラグインが不必要に update を呼び出したり、ソースが一切変わっていないのにプロセス外の Typescript コンパイラを呼び出したりしているかもしれない。 super shell 現在実行中のタスクを表示する “super shell” はこれらの問題を解決する。1s 以内に実行するタスクは画面には表示されず、長時間走っているタスクはカウントアップする時計が表示される。 初めて僕がこのような機能に気付いたのは Gradle の “rich console” だ。Buck もこれを実装していて、“super console” と呼ばれているらしいので、僕もその名前を借りることにした。 super shell の実装方法 一ヶ月ぐらい前に Scala で書くコンソール・ゲームを書いたが、実はそれはこの機能のための予備研究だった。 super shell は二部から構成される。第一にロガーを変更して、ログがターミナルの上方向へ移動するようにする。このテクニックは「コンソール・ゲーム」で既に解説したが、ScrollUp を使うことでターミナルで同じ位置を保ったままログを表示させ続けることができる。-Xlint, -Xfatal-warnings, そして Scalafix を用いた Scala の厳格化
コンパイルする、さもなければコンパイルしない。警告などいらない。最近気に入っている Scala コンパイラのフラグは "-Xlint" と "-Xfatal-warnings" の 2つだ。 以下は、サブプロジェクトと共に使えるセッティングの例だ: ThisBuild / scalaVersion := "2.12.6" lazy val commonSettings = List( scalacOptions ++= Seq( "-encoding", "utf8", "-deprecation", "-unchecked", "-Xlint", "-feature", "-language:existentials", "-language:experimental.macros", "-language:higherKinds", "-language:implicitConversions" ), scalacOptions ++= (scalaVersion.value match { case VersionNumber(Seq(2, 12, _*), _, _) => List("-Xfatal-warnings") case _ => Nil }), Compile / console / scalacOptions --= Seq("-deprecation", "-Xfatal-warnings", "-Xlint") ) lazy val foo = (project in file("foo")) .settings( commonSettings, name := "foo", ) -Xlint とは?git gone: stale なローカルブランチのクリーンアップ
GitHub の pull request を中心に作業していると、やたらといらないブランチがローカルに溜まってくる。本稿では、このいらないローカルブランチを掃除する方法をみてみる。 基本的に 2つの戦略があると思う: “master” ブランチを選んで、そこにマージ済みのものを削除する GitHub 上で既にブランチは削除されている前提で、リモートの “origin” にはもう無いローカルのブランチを削除する Erik Aybar さんの Git Tip: Deleting Old Local Branches というブログ記事は第2の方法をとっている。 This just helped clean up 150+ old local branches for me this morning, so I thought I should share! #githttps://t.co/VLKLtl5inp — Erik Aybar (@erikaybar_) January 31, 2017 git gone git gone は、Erik Aybar さんのテクニックをベースに僕が書いたカスタム git コマンドだ。Bash でスクリプト書くのは不慣れなので Google とか Stackoverflow を見ながら書いたが、一応動いてくれていると思う。eed3si9n/git-gone にソースを貼ったのでそれを ~/bin など適当な場所に git-gone として保存する。 使い方は git gone と打てば出てくるようにした:Scala で書くコンソール・ゲーム
最近リッチなコンソールアプリのことを考えることがある。ただ行を追加していくんじゃなくて、グラッフィック的な事をやっているアプリだ。多分テトリスを書けるぐらいの情報は集めたのでここにまとめておく。 ANSI X3.64 control sequences ターミナル画面の任意の位置にテキストを表示するためには、まずターミナル (terminal) とは何かを理解する必要がある。1960年代中盤に各社は PDP-8 などいったミニコンピューターを発売し、これらは PDP-11、VAX-11 と続く。これらは冷蔵庫ぐらいの大きさのコンピューターで、「計算機センター」が購入し、RT-11 や元祖 UNIX system といったオペレーティング・システムを走らせ、同時に多くのユーザ (12 ~ 数百人?) をサポートすることができた。ミニコンピュータへ接続するために、ユーザはモノクロ画面とキーボードを合わせた物理端末を使った。端末の中でも最も有名なのは 1978年に DEC社が発売した VT100 だ。 VT100 は 80x24文字をサポートし、カーソル制御に ANSI X3.64 標準を採用した初期のターミナルの一つだ。言い換えると、プログラムは文字の列を出力することで任意の位置にテキストを表示することができた。現在の「ターミナル」アプリケーションは、「ターミナル・エミュレータ」と呼ばれることがあるが、それは VT100 といった物理端末をエミュレートしていることに由来する。 VT100 制御シーケンスのレファレンスは以下が参考になる: Console Virtual Terminal Sequences - Windows Console 11.1 Control Sequences - Screen User Manual CUP (Cursor Position) ESC [ <y> ; <x> H CUP Cursor Position *Cursor moves to <x>; <y> coordinate within the viewport, where <x> is the column of the <y> linesbt 1.2.0
@eed3si9n 著 皆さんこんにちは。Lightbend Tooling team にかわって sbt 1.2.0 をアナウンスします。これは sbt 1 のフィーチャーリリース第二弾で、バイナリ互換性は維持しつつ新機能にフォーカスを当てたリリースとなっている。sbt 1 は Semantic Versioning にもとづいてリリースされるので、プラグインは sbt 1.x シリーズ中機能することが期待されている。 2018年7月31日に 1.2.0 final 版がリリースされた。 2018年7月6日までに大きな問題が見つからなければ、1.2.0-RC1 は 1.2.0 final 版となる予定だ。 sbt 1.2 の主な新機能はクロスJDK forking、composite project、そして実験的な thin client だ。sbt 1.1 から 6ヶ月の間他にも色々なバグ修正や改善点がたまっていた。 プラグイン開発のための SbtPlugin SbtPlugin は、プロジェクトが sbt plugin であることを宣言するためのプラグインだ。これは自動的に scripted test を導入して、sbtPlugin := true を設定する。 lazy val root = (project in file(".")) .enablePlugins(SbtPlugin) 互換性に関する注意: ScritpedPlugin は triggered plugin ではなくなった。 #3875 by @eed3si9n君達の JDK は全て jabba がいただいた
OpenJDK 11-ea, GraalVM, Eclipse OpenJ9 を試してみたり、未だに OpenJDK 6 でビルドしなければいけなかったりしたとしても jabba なら万全だ。jabba は Stanley Shyiko (@shyiko) さんが作ったクロスプラットフォームな Java のバージョンマネージャーだ。 AdoptOpenJDK 8 and 11 以下は jabba を使って Travis CI 上で AdoptOpenJDK 8 と 11 を用いてクロスビルドする方法だ: sudo: false dist: trusty group: stable language: scala scala: - 2.12.7 env: global: - JABBA_HOME=/home/travis/.jabba matrix: include: - env: - TRAVIS_JDK=adopt@1.8.192-12 - env: - TRAVIS_JDK=adopt@1.11.0-1 before_install: - curl -sL https://raw.githubusercontent.com/shyiko/jabba/0.11.0/install.sh | bash && . ~/.jabba/jabba.sh install: - $JABBA_HOME/bin/jabba install $TRAVIS_JDK - unset _JAVA_OPTIONS - export JAVA_HOME="$JABBA_HOME/jdk/$TRAVIS_JDK" && export PATH="$JAVA_HOME/bin:$PATH" && java -Xmx32m -version script: sbt -Dfile.Expecty を用いた power assert を復活させる
先週は sbt-sriracha を用いたソース依存をテストに使う方法を紹介した。今週は Expecty を使って power assert をする方法を見ていく。 power assert (もしくは power assertion) は assert(...) 関数の変種で、自動的に詳細なエラーメッセージを表示してくれる。これは、Peter Niederwieser (@pniederw) さんがまず Spock のために実装して、2009 年に Groovy 1.7 に取り込まれた。power assert は Ruby、JavaScript、Rust など他の言語にも広まっている。 従来の assert 文 例えとして a * b を考える。従来の assert を使った場合以下のように書く: scala> assert(a * b == 7, s"a = $a; b = $b; a * b = ${a * b}") java.lang.AssertionError: assertion failed: a = 1; b = 3; a * b = 3 ごちゃごちゃと全部の変数への検査をログやエラーメッセージに書くといったことが往々にして行われる。sbt-sriracha を用いたホットなソース依存
ソース依存性はかなり前から sbt に存在するが、あまりドキュメント化されていない機能の一つだ。 immutable なソース依存 以下のようにして scopt コマンドラインパーシングライブラリの最新のコミットへのソース依存を宣言できる。 lazy val scoptJVMRef = ProjectRef(uri("git://github.com/scopt/scopt.git#c744bc48393e21092795059aa925fe50729fe62b"), "scoptJVM") ThisBuild / organization := "com.example" ThisBuild / scalaVersion := "2.12.2" lazy val root = (project in file(".")) .dependsOn(scoptJVMRef) .settings( name := "Hello world" ) sbt を起動して compile を走らせると、sbt は自動的に scopt/scopt をステージング・ディレクトリにクローンして、ビルドをつなぎ合わせる。 そのため sbt バージョンが互換である必要があり、また、要らないトリガープラグインが混入する可能性があることにも注意してほしい。 もう一つの制約は、最初のクローンの後はステージング・ディレクトリが更新されないことだ。 ハイブリッド依存性 僕が代わりにほしいのはハイブリッド依存性で複数のリポジトリをつなぎ合わせて、コードを書いてテストを走らせることができるが、公開時には Maven のバイナリ依存性となるものだ。 これを実現するために sbt-sriracha という実験的なプラグインを書いた。project/plugins.sbt に以下を追加する: addSbtPlugin("com.eed3si9n" % "sbt-sriracha" % "0.1.0") すると以下のように書けるようになる: lazy val scoptJVMRef = ProjectRef(workspaceDirectory / "scopt", "scoptJVM") lazy val scoptJVMLib = "com.Bash からの Java バージョンの検知
昨日 Travis CI を用いてクロス JVM テスト する方法を書いた。 Travis CI を用いた macOS 上での Scala アプリのテスト Travis CI を用いて macOS 上で Scala アプリのテストを行うことも可能だ。これは Lars さんと Muuki さんの方法 Testing Scala programs with Travis CI on OS X をアレンジしたものだ。 dist: trusty language: scala matrix: include: ## build using JDK 8, test using JDK 8 - script: - sbt universal:packageBin - cd citest && ./test.sh jdk: oraclejdk8 ## build using JDK 8, test using JDK 8, on macOS - script: - sbt universal:packageBin - cd citest && .Travis CI を用いたクロス JVM テスト
Oracle は non-LTS JDK を 6ヶ月おき、LTS JDK を 3年おきにリリースする計画だ。また、今後は OpenJDK に集約されていくらしい。計画どおりにいけば、JDK 9 は 2018年3月に EOL、JDK 10 は 2018年3月にリリースされ、2018年9月に EOL、そして 2018年9月に JDK8 をリプレースする LTS JDK 11 は 2021年まで続くということになる。 今後立て続けにリリースされる JDK に備えて、Travis CI を使ってアプリを JDK 8, JDK 9, そして JDK 10 Early Access でテストする方法を紹介する。 dist: trusty language: scala matrix: include: ## build using JDK 8, test using JDK 8 - script: - sbt universal:packageBin - cd citest && ./test.sh ## build using JDK 8, test using JDK 9 - script: - sbt universal:packageBin - jdk_switcher use oraclejdk9 - cd citest && .sbt-nocomma を用いたカンマの消去
2016年8月 SIP-27 末尾のカンマ (trailing commas) に関するディスカッションのときに思いついたのは一部のカンマの用法をセミコロンと統一できれば、セミコロン推論を流用することができるんじゃないかということだ。 Aug 10 2016 20:46: 特に可変長引数 (vararg) の区切り文字としてセミコロンを許せば便利そうだ。しかし、実際にはそれはうまくいかない。@Ichoran さんが具体例を用いて指摘してくれた: Seq( a b c ) これは現状の Scala では Seq(a.b(c)) と解釈される。 2018年1月 最近 @swachter さんが Comma inference というスレッドを立てたので、再びこの話題のことを思い出した。 Scala には「セミコロン推論」というよく知られた機構があるが、パラメータや引数のリストに同様の機構を「コンマ推論」として導入できれば便利ではないだろうか。 僕のこれに対する返答は: Scala (言語仕様としても我々ユーザとしても) は 1つ以上の句読点推論を取り扱うのは難しいと思うが、試す価値のあるトリックはあるかもしれない。 パーサーを通過する必要があるので、Scala として合法な「形」(shape) がまず必要になる。例えば、 scala> List({ 1 2 3 }) res1: List[Int] = List(3) 以上は合法な Scala だ。中括弧はコンパイラの中では Block データ型としてパースされる。可変長 Int* の引数を受け取って、もし Block が渡された場合には各ステートメントを展開するマクロを定義することは可能かもしれない。 つまり、言語の変更を目指すかわりに、構文木の書き換えを試してみることを提案したい。ブロック { ... } を使うことで Rex さんが指摘してくれた問題も回避できる。 scala> :paste // Entering paste mode (ctrl-D to finish) class A { def b(c: Int) = c + 1 } lazy val a = new A lazy val b = 2 lazy val c = 3 // Exiting paste mode, now interpreting.sbt-sticker
以前ツイートしたとおり、sbt ステッカーを自作した。

猫番: 17日目
猫番: 17日目を書いた。始対象と終対象、積、双対性、余積など抽象構造を見ていきつつ、Either を coproduct として使う方法を紹介します。
Neovim と sbt server

ファイルパスの URI 参照へのエンコード方法
本稿では古くて新しい問題であるファイルパスの Uniform Resource Identifier (URI) へのエンコード方法について議論する。 2017年現在、権威ある情報の元は Matthew Kerwin 氏によって書かれた RFC 8089 - The “file” URI Scheme だ。 RFC 8089 The "file" URI Scheme https://tools.ietf.org/html/rfc8089 Wow, it actually happened. — Matthew Kerwin (@phluid61) February 18, 2017 未来の読者の人は “file URI scheme RFC” で検索して最新版を探してほしい。プログラマの人は RFC を読んで下さい。この覚え書きは URI エンコーディングに関連した問題の認識を高めるためのものだが、RFC の代替とはならない。 最近 file:/foo/bar がパースできないというプラットフォーム間の相互乗り入れ問題に出くわした。ファイルパスを URI として表現するのに関連した問題に悩まされるのはこれが最初でもない。ファイルシステムという概念は 1960年代に遡り、1990年代から URL があることを考えると、このコンセンサスが取れていないというのは意外なことだ。しかし、十進法小数のように、深く掘り下げたり、データを交換しはじめると、Matrix のほころびが見えてくるのかもしれない。 tl;dr 2020年11月現在での実装: import java.io.File import java.net.{ URI, URISyntaxException } import java.util.Locale private val isWindows: Boolean = sys.Sublime Text 3 と sbt server
Tech Hub blog にて sbt server を VS Code と併用して実行中の sbt セッションからコンパイラエラーを表示できることをデモした。本稿では Sublime Text 3 でそれをやってみる。 sbt server のための Sublime Text 3 のセットアップ方法 まずは Sublime Text 3 に tomv564/LSP プラグインを追加する。 cd ~/Library/Application\ Support/Sublime\ Text\ 3/Packages git clone https://github.com/tomv564/LSP.git ‘Preferences > Package Control > Satisfy Dependencies’ を実行する 次に sbt-server-stdio.js をダウンロードして ~/bin/ もしくは普段スクリプトを保存している場所に保存する。sbt server は、POSIX システムではデフォルトで Unix ドメインソケット、Windows では名前付きパイプを用いるが、エディタは基本的に標準出入力を期待しているみたいだ。これは VS Code エクステンション用に僕が書いた実行中のソケットを発見して、標準出入力でフロントを作る Node スクリプトだ。 これで Language Server クライアントの設定ができるようになった。 ‘Preferences > Package Settings > LSP > Settings’ を開く。Ergodox

sbt 1.1.0-RC1 の sbt server と統一スラッシュ構文
Lightbend の技術系ブログ Tech Hub blog に sbt 1.1.0-RC1 with sbt server and slash syntax という記事を書いたので、訳しました。 @eed3si9n 著 皆さんこんにちは。Lightbend Tooling team にかわって sbt 1.1.0-RC1 をアナウンスします。これは、sbt 1 初のフィーチャーリリースで、バイナリ互換性は維持しつつ新機能にフォーカスを当てたリリースとなっている。 sbt 1 は Semantic Versioning にもとづいてリリースされるので、プラグインは sbt 1.x シリーズ中機能することが期待されている。2017年12月14日までに大きな問題が見つからなければ、1.1.0-RC1 は 1.0.0 final 版となる予定だ。 sbt 1.1 の主な新機能は統一スラッシュ構文 (unified slash syntax) と sbt server だ。これらは両方とも僕が個人的にしばらく関わってきた機能だが、sbt 1.0 には入れずに延期させたものだ。そのため、やっとこれらを世に出せるのがひとしお嬉しい。 セッティングキーの統一スラッシュ構文 sbt の 1ユーザとして、sbt シェルと build.sbt でセッティングとタスクキーに 2つの表記方法があるのが、sbt の学習を難しくしている理由だと長いこと思ってきた。コミュニティーの皆さんと議論を重ね、いくつかのプロトタイプを作った後、sbt 1.1.0-RC1 より統一スラッシュ構文がサポートされることになった。 (sbt 0.13 表記も引き続き動作するのでご心配無く) build.sbt と sbt shell の両方において、セッティングはスコープ軸をスラッシュで分けて以下のように書くことができる:sbt 1.0.4 hotfix とパフォーマンスまわりの修正
Lightbend の技術系ブログ Tech Hub blog に sbt 1.0.4 hotfix and the performance fixes という記事を書いたので、訳しました。 @eed3si9n) 著 皆さんこんにちは。アメリカに住んでいる人たちは、良い感謝祭 (Thanksgiving) の連休すごせたでしょうか。 遠くからの親戚や友達が集まって食事を作ったり、小咄を交わす年中行事という意味では、日本の正月休みに近いものがあると思う。 あと、sbt 1.0.4 をリリースしたこともアナウンスします。これは sbt 1.0.x シリーズの hotfix で、バグ修正にフォーカスを当てたバイナリ互換リリースだ。 sbt 1 は Semantic Versioning にもとづいてリリースされるので、プラグインは sbt 1.x シリーズ中機能することが期待されている。 パフォーマンスデグレの修正 感謝祭ということで、お世話になっている人たちの事を考えるわけだけど、僕は Scala のツーリングエコシステムにコントリビュートしてくれている皆さんに感謝している。これは、sbt へのコードのコントリビュートだけじゃなく、考えさせられるブログ (Haoyi さんの So, what’s wrong with SBT? など)、トーク (Jeff さんの Beyond the Build Tool など)、ドキュメンテーション、IDE/エディタ統合、や代替ビルドツール (Chris さんの cbt など) も含めている。冷笑的に「sbt はダメ」って言って終わりにするんじゃなく、この人たちは腕をまくって、sbt そのものを直したり、代替案を考え出しているからだ。 sbt 1 に関連してパフォーマンスのデグレが報告されているが、何人もの人が飛び込んで取り組んでくれている。 Scala Center の Jorge さん (@jvican) は性能向上関係を色々やっていて、sbt 1.sbt 1 マイグレーション状況報告と 1.0.2 hotfix
Lightbend の技術系ブログ Tech Hub blog に sbt 1 migration status and 1.0.2 hotfix という記事書いたので、訳しました。 @eed3si9n 著 こんにちは。sbt 1.0.0 リリース後に何があったかのレポートだ。 僕たちの sbt 1 へのマイグレーションのプランは以下のようになっている: sbt 1.0.0 をリリースする。 コミュニティーの皆さんと一緒にプラグインを全部移行させる。 バグを修正する。 ライブラリのビルドを移行させる。 プラグインの移行 プラグインの移植の進捗を追跡するために、知られているプラグインの一覧を作って GitHub star 順にソートした。これは、ドキュメンテーションをスクリーンスクレイピングしたのを元に、手動でも色々追加してある。ここに書かれた 258個のプラグインは新しいのや古いのも混ざっていて、sbt プラグインエコシステムの裾野の広さがよく分かる。 本日付では、一覧のうち 70個のプラグインが「リリース済み」となっていて、他にもプラグイン作者やアクティブなユーザによって移行途上の様々なステージにあるものが色々ある。中でも吉田さん (xuwei-k) は、複数箇所に同時に存在するかのような勢いで多くのプラグインの移植作業を行っていた。以下は僕が見つけた範囲: https://github.com/scalikejdbc/scalikejdbc/pull/714 https://github.com/thesamet/sbt-protoc/pull/30 https://github.com/sbt/sbt-unidoc/pull/42 https://github.com/ktoso/sbt-jmh/pull/121 https://github.com/xuwei-k/sbt-class-diagram/ https://github.com/rtimush/sbt-updates/pull/75 https://github.com/sbt/sbt-dirty-money/pull/12 https://github.com/sbt/sbt-site/pull/107 https://github.com/sbt/sbt-ghpages/releases/tag/v0.6.2 https://github.com/sbt/sbt-multi-jvm/pull/34 https://github.com/sbt/sbt-testng/issues/19 https://github.com/sbt/sbt-onejar/pull/34 ありがとうございます! sbt hotfix 1.0.2 あと、sbt 1.0.2 をリリースしたこともアナウンスします。これは sbt 1.0.x シリーズの hotfix で、バグ修正にフォーカスを当てたバイナリ互換リリースだ。 ターミナルの echo 問題の修正。 #3507 by @kczulko deliver タスクの修正、および名前的に改善した makeIvyXml というタスクの追加。 #3487 by @cunei 廃止勧告が出ていた OkUrlFactory のリプレースとコネクションのリークの修正。 lm#164 by @dpratt セッティングキーに対して DSL チェッカーが偽陽性を出していたことの再修正。 #3513 by @dwijnand run と bgRun がクラスパスのディレクトリ内の変更を検知していなかったことの修正。 #3517 by @dwijnand ++ を修正して crossScalaVersion が変更されないようにした。 #3495/#3526 by @dwijnand sbt server がメッセージを逃すのを修正した。 #3523 by @guillaumebort consoleProject の再修正。 zinc#386 by @dwijnand sbt.sbt を用いた Scala language server
sbt 1.0 がリリースされてからもう一ヶ月になり、やっと少し落ち着いて sbt server のことを考えれるようになった。週末の時間をさいて最近 Scala language server (言語サーバー) を sbt server 上にハックしている。 language server って何? language server とは、Visual Studio Code、 Eclipse Che、 Sublime Text 3 といったエディタに対して Language Server Protocol を通じて何らかの言語サービスを提供するプログラムのことだ。演算の一例を挙げると textDocument/didOpen はエディタ内でソースファイルが開かれたことをサーバーに伝える。 これは賢いアイディアで、エディタ作者を (従来の IDE のように) 単一の言語にべったりになることから解放し、また同時に言語プロバイダーは「演算」に専念すればいいようになる。JSON ベースのプロトコルなので、web アプリのバックエンドを書いている感覚に近い。もう一つ嬉しいのは、一度に全ての機能を提供しなくてもいいことだ。 Scala language server は、Iulian Dragosさんによる dragos-vscode-scala という実装が既にあって、それは ENSIME をバックエンドとして使う。僕は、だいたい Sublime と sbt だけでコードを書いているので、中抜きして直接 Zinc のイベントを使えばいいんじゃないかと思った。 sbt server sbt server の考え方としては、ユーザの演算はコマンドとクエリとして表現でき、コンソールに表示される様々な出力はイベントとして表現できるというものだ (sbt server リブートも参照)。多くの場合、ビルドユーザが価値を見出すのはタスクの戻り値ではなく、コンパイラの警告やテストの出力といったコンテンツだ。 この設計は、language server protocol にもよくマッチしていて、彼らはストリームされるイベントに対して「通知」 (notification) という用語を使っている。Persistent Versioning
本稿では、僕が Persistent Versioning と呼んでるバージョン方法を紹介する。本稿中に出てくるアイディアの多くは新しくもなければ僕が考案したものでもない。既に名前があるならば是非教えてほしい。 2015年に Jake Wharton (@JakeWharton) さんが メジャーバージョンアップデートのための Java 相互互換方針 (Java Interoperability Policy for Major Version Updates) というブログ記事を書いた: A new policy from @jessewilson and I for the libraries we work on to ensure major version updates are interoperable: https://t.co/zKqYRwrXmq — Jake Wharton (@JakeWharton) December 11, 2015 Java パッケージ名にバージョン番号を含むように名前を変える。 これによって、間接的依存ライブラリが複数のバージョンを持つ場合の API 互換性の問題が即時に解決する。同じクラスパスから各々のクラスを相互干渉することなく読み込むことができる。(中略) (メジャーバージョンが 0 か 1 のライブラリはこの方針を飛ばして、メジャーバージョンが 2 に上がってから始めてもいい。) Maven 座標の group ID の一部としてライブラリ名を含ませること。 たとえ単一のアーティファクトしか持たないプロジェクトでも、group ID にプロジェクト名を入れておくと将来的に複数のアーティファクトを持ったときにルートの名前空間を散らかさなくてもいい。最初から複数のアーティファクトを持つ場合は、Maven Central などにおいてアーティファクトをまとめる方法となる。 ….sbt 1.0.0 はじめました
sbt 1.0.0 Lightbend の技術系ブログ Tech Hub blog に sbt 1.0.0 is now available という記事を書いたので、訳しました。 詳細は sbt 1.0.0 リリースノートを見てください。 Eugene Yokota (@eed3si9n) 2017年8月11日 著 Lightbend社 Tooling チームに代わって sbt 1.0.0 のリリースを発表します! Mark Harrah さんが 2008 年に最初にリリースした sbt から数えると、sbt 1 は何年もかけて開発された大きな里程標であると言える。直近のメジャーリリースの sbt 0.13.x も、最初のリリースが 2013年8月なので 4年間続いたことになる。 Lightbend社 Tooling チームは 0.13 のメンテと並行して sbt 1 へ向けての進化も継続してきた。この期間中に sbt new、AutoPlugin、cached resolution などが追加された。また、コミュニティによって何百ものプラグインが書かれ、sbt の能力はただのシンプルビルドツールの能力を拡張したものとなっていった。 主な機能 sbt 1 は Scala 2.12 を採用したため、ビルド内でやっとモダンな Scala が使えるようになった! これによって 2.10 をサポートをするプレッシャーが軽減するので、プラグイン作者やライブラリ作者にとっても朗報だ。 sbt 1 は Zinc 1 という、クラスベースの name hashing を使う高速なインクリメンタル (差分) コンパイラを導入する。Scala のインクリメンタル・コンパイラを独り占めにするにはあまりにも重要だと思ったので、Zinc 1 は sbt/zinc という別のリポジトリに分けられ、Lightbend 社と Scala Center の共同で管理されている。 sbt 1 はデフォルトで Gigahorse HTTP クライアント (内部は Square OkHttp) を使ってアーティファクトを並列ダウンロードする。Library Mangement API も追加され、将来の 1.Travis-CI からの (website の) 自動公開
GitHub Pages は OSS プロジェクトのドキュメントをホスティングするのに便利だ。 ここでは Travis CI を使って pull request の merge 時に自動デプロイする方法を説明する。 1. 新しい RSA キーを適当なディレクトリ内で生成する。 プロジェクト外にまずはディレクトリを作る。 キーの名前は deploy_yourproject_rsa などとつけて、他のキーと区別できるようにする。 $ mkdir keys $ cd keys $ ssh-keygen -t rsa -b 4096 -C "yours@example.com" Generating public/private rsa key pair. Enter file in which to save the key (/Users/xxx/.ssh/id_rsa): deploy_website_rsa Enter passphrase (empty for no passphrase): パスフレーズは空のままにする。 2. ウェブサイトプロジェクトに移動する。 プロジェクトに移動して、ブランチを立てて、.travis という名前のディレクトリを作る。 $ cd ../website $ mkdir .travis 3. travis ユーティリティをインストールして、秘密鍵を暗号化する。 travis encrypt-file --repo foo/website .Atreus のためのトレイ
前回 Atreus の組み立てについて書いたときに、キーボードの配置についてちょっと書いた。 さらにたとえレイアウトを克服して様々なシンボルの場所を暗記しても残っている問題が一つあって、それは置き場所だ。ラップトップと自分の間に置くと画面が遠すぎる気がする。 この問題の解決方法として、MacBook Pro のキーボード上に Atreus を配置できるようにトレイを作ってみた。 Great post; thanks. For the positioning, have you tried disabling the internal keyboard and placing the Atreus on top of the laptop? — technomancy (@technomancy) June 19, 2017 きっかけとなったのは、Atreus の作者の @technomancy さんに Atreus を MacBook Pro のキーボード上に直接乗せてみてはどうかの提言からだ。彼の Thinkpad は丈夫なのかもしれないが、僕の新品のラップトップの上に直乗せなんて冗談じゃない。 材料 1 “1/4 in x 6 in x 48 in” Oak hobby board ($8.52) 1 3M Garnet Sandpaper Med 100 grit ($3.97) 1 Sandpaper 200 grit 1 Small Parts General Purpose Rubber, 70A Durometer, Smooth Finish, Adhesive Backed, 0.Atreus
しばらく前にキットで買った Atreus を昨日の夜作り終えた。詳細はこんな感じ: Matias Quiet Click スイッチのオプションを選んだ(スライダーはグレー)。クリックという名前は付いているがクリック感は無いことに注意。 修飾キーには Matias Quiet Linear スイッチを使用(スライダーは赤)。 いわゆる ortholinear 系の格子状の、スプリットレイアウトで、42 のキーがある。 マホガニー材の合板。 材料 キットには Arteus キーボードを組み立てるのに必要なものはほぼそろっている。自分で用意する必要があるのはラッカー、半田ごて、ハンダ、とニッパーだ。 Minwax Clear Aerosol Lacquer, Clear Gloss Hakko Digital FX888D & CHP170 bundle, includes Soldering Station & CHP170 cutter Hakko T18-C2 - T18 Series Soldering Tip for Hakko FX-888/FX-8801 DMiotech 0.8mm 50G 63/37 Rosin Core Tin Lead Soldering Solder Wire ここで注意してほしいのは Matias社のスイッチは、80年代とか 90年代に Apple Standard Keyboard などで採用された日本のアルプス電気の Alps SKCM のクローンであることだ。そのため、Cherry MX スイッチ用のおしゃれなキーキャップは一切使うことができない。それがやりたい人は Cherry 互換のパーシャルキットを注文する必要がある。Gigahorse 0.3.0
Gigahorse 0.3.0 をリリースした。Gigahorse が何かはドキュメンテーションをみてほしい。
OkHttp サポート
0.3.0 は Square OkHttp サポートを追加する。 Gigahorse-OkHttp は Scala 2.10, 2.11, 2.12 向けにクロスビルドされている。
JavaDoc によると、OkHttpClient
のインスタンスは close しなくてもいいらしい。
scala> import gigahorse._, support.okhttp.Gigahorse
import gigahorse._
import support.okhttp.Gigahorse
scala> import scala.concurrent._, duration._
import scala.concurrent._
import duration._
scala> val http = Gigahorse.http(Gigahorse.config) // don't have to close
http: gigahorse.HttpClient = gigahorse.support.okhttp.OkhClient@23b48158
sbt 1.0 ロードマップと beta-1
Lightbend の技術系ブログ Tech Hub blog に sbt 1.0 roadmap and beta-1 という記事書いたので、訳しました。 @eed3si9n 著 sbt 1.0 はかれこれ数年間制作中という状態が続いていて、コミュニティーの中には「もう出ないのでは」という懐疑派がいてもおかしくない。そのような懸念は以下の論点によって払拭できると思っている: 本来 1.0 に予定していた (AutoPlugin や Dotty サポートのような) 機能はすでにテクノロジー・プレビューとして 0.13 系にてリリースされている。 1.0 に予定されていた機能のうち、より意欲的なものは延期または機能を縮小して 1.0 が早期に実現できるようにした。(キャッシュ化されたコンパイルや Ivy の置き換えなど) sbt 1.0 はベーパーウェアではない。最新だと 1.0.0-M5 などマイルストーンが出ていて、今すぐ試すことができる。 そのため、2017年夏までに sbt 1.0 プランを実現可能だと思っている。 ハイライト sbt 1.0 は、向こう数年間続く安定版であることと、sbt 0.13 系からのスムーズな移行が可能であることを目標とする。sbt 0.12 スタイルの演算子や Build トレイトは削除される。本来 1.0 に予定していた機能はすでにテクノロジー・プレビューとして 0.13.x シリーズにてリリースされている。 sbt 1.0 における利点をまとめると: ビルド定義やプラグインに Scala 2.12 が使えるようになる 大規模コードベースにおいて高速化が見込まれる新インクリメンタルコンパイラ、Zinc 1 今後の IDE 統合の改善の下地となる sbt server タイミング sbt 1.sbt-sidedish を使ったアプリのダウンロードと実行
sbt プラグインから JAR をダウンロードしてそれを実行したいという要望が出てきてる。 最近だと Brooklyn での nescala で Shane Delmore (@shanedelmore) さんに聞かれた。 アンカンファレンスのセッションでデモっぽいものをやっつけで作ったけども、家に帰ってからも色々いじったのでここに報告する。 sbt-sidedish sbt-sidedish はアプリをサイドメニュー的に落としてきて実行するためのプラグイン作者のためのツールキットだ。それそのものは特にプラグインを定義しない。 rewritedemo、コマンドラインアプリ サイドで走らせたいアプリを作る。これは Scala 2.11 や 2.12 を使ってもいい。 Scalafix を使って import 文を追加するデモアプリを書いた。Scalafix は Scala コードの書き換えツールとライブラリで scala.meta を使っている。詳細は Scalafix のドキュメンテーションとソースを参照。 sbt-rewritedemo、sbt プラグイン 次に、rewritedemo アプリをあるサブプロジェクト相手に実行して別のサブプロジェクトを導出したいとする。 sbt-sidedish を使って以下のようなプラグインが書ける。 package sbtrewritedemo import sbt._ import Keys._ import sbtsidedish.Sidedish object RewriteDemoPlugin extends AutoPlugin { override def requires = sbt.plugins.JvmPlugin object autoImport extends RewriteDemoKeys import autoImport._ val sidedish = Sidedish("sbtrewritedemo-metatool", file("sbtrewritedemo-metatool"), // scalaVersion "2.猫番: 16日目
猫番: 16日目書いた。
sbt 0.13.15 リリースノート
互換性に影響のある新機能、変更点、バグ修正 sbt 0.13.14 は Maven のバージョンレンジをできる限り取り除く。詳細は後ほど。 改善点 予備として JDK 9 との互換性を追加した。この機能は 0.13.14 以降のネイティブパッケージを必要とする。 #2951/143 by @retronym オフライン・インストール用に “local-preloaded” レポジトリを追加する。詳細は後ほど。 ウォーミングアップされた JVM に留まるように、バッチモードで sbt を実行すると [ENTER] を押して shell に切り替えるよう通知するようにした。 #2987/#2996 by @dwijnand .taskValue を使わずに sourceGenerators += Def.task { ... } と書けるようにするために Append のインスタンスを追加した。 #2943 by @eed3si9n JUnitXmlTestsListener が生成する XML が無視、スキップ、保留状態のテストにそれぞれフラグを立てるようにした。 #2198/#2854 by @ashleymercer プロジェクトが Dotty を使ってコンパイルしていると検知した場合に、自動的に scalaCompilerBridgeSource を設定して、Dotty プロジェクトのボイラープレートを軽減するようにした。ただし、sbt における Dotty サポートは現在実験的であり、正式にはサポートされていないことに注意。詳細は dotty.epfl.ch 参照。 #2902 by @smarter sbt new のレファレンス実装である Giter8 を 0.Contraband、case class の代替案
しばらく考えている疑問がいくつかある: データや API はどう書かれるべきだろうか? そのデータは Java や Scala ではどう表現されるべきか? そのデータは JSON などのワイヤーフォーマットにどう変換することができるか? そのデータをどうやってバイナリ互換性を崩さずに進化させることができるか? case class の限界 Scala でデータ型を表現する慣用的な方法は sealed trait と case class だが、バイナリ互換性を保ったままフィールドを追加することができない。簡単な Greeting という case class を例に取って、それがどのようなクラスとコンパニオンオブジェクトに展開されるか考察してみよう: package com.example class Greeting(name: String) { override def equals(o: Any): Boolean = ??? override def hashCode: Int = ??? override def toString: String = ??? def copy(name: String = name): Greeting = ??? } object Greeting { def apply(name: String): Greeting = ?sbt 0.13.x、sbt サーバー、sbt 1.0 の動向
同僚の Dale Wijnand (@dwijnand) と一緒に ScalaSphere でトークをしてきた。The state of sbt 0.13, sbt server, and sbt 1.0 (ScalaSphere ver):
Gigahorse 0.2.0
Gigahorse 0.2.0 をリリースした。新機能は 2つのバックエンドを選べるようになったことだ。 @alexdupre さんが AHC 1.9 から Netty 4 ベースの AHC 2.0 への移行をコントリビュートしてくれた。#12
さらに、#15 で僕が実験的な Akka HTTP サポートを追加した。
詳しくは Gigahorse ドキュメントを参照してほしい。
Scala 2.12.0 リリースノート
昨日リリースされたばかりの Scala 2.12.0 のリリースノートを翻訳しました。 Lightbend 社 Scala チームのコンパイラ魂を感じ取れる、マニアな内容になっています。
Scala 2.12.0 がリリースされました!
Scala 2.12 コンパイラは Java 8 から使えるようになった新しい VM 機能を利用するために、完全なオーバーホールが行われた。
- トレイトは、デフォルトメソッド付きのインターフェイスに直にコンパイルされる。これはバイナリ互換性と Java との相互運用性を向上させる。
- Scala と Java 8 の相互運用 (interop) という点では、関数を受け取るメソッドが両方向からもラムダ構文で呼び出せるようになったので関数型なコードにおいても改善した。Scala 標準ライブラリの
FunctionN
クラス群は、Single Abstract Method (SAM) 型となり、全ての SAM型は、型検査からコード生成におけるまで統一的に取り扱われる (クラスファイルは生成されず、代わりにinvokedynamic
が用いられる)。
gigahorse-github 0.1.0
gigahorse-github 0.1.0 をリリースした。これは、Github API v3 のための Gigahorse プラグインだ。
Gigahorse 0.1.0
更新: Gigahorse 0.1.1 を使ってください。
Gigahorse 0.1.0 をリリースした。これは Scala のための HTTP クライアントで、内部にAsync Http Client を使っている。詳しくは Gigahorse ドキュメントを書いたので、それを参照してほしい。ライブラリがどういう感じなのかを例でみるとこんな感じだ。
scala> import gigahorse._
scala> import scala.concurrent._, duration._
scala> Gigahorse.withHttp(Gigahorse.config) { http =>
val r = Gigahorse.url("http://api.duckduckgo.com").get.
addQueryString(
"q" -> "1 + 1",
"format" -> "json"
)
val f = http.run(r, Gigahorse.asString andThen {_.take(60)})
Await.result(f, 120.seconds)
}
registry and reference パターン
ここ最近考えている「パターン」があって、オブジェクトを永続化/シリアライゼーションするみたいな状況で出てくる。 問題提起として、以下のような case class を考えてみてほしい: scala> case class User(name: String, parents: List[User]) defined class User scala> val alice = User("Alice", Nil) alice: User = User(Alice,List()) scala> val bob = User("Bob", alice :: Nil) bob: User = User(Bob,List(User(Alice,List()))) scala> val charles = User("Charles", bob :: Nil) charles: User = User(Charles,List(User(Bob,List(User(Alice,List()))))) scala> val users = List(alice, bob, charles) users: List[User] = List(User(Alice,List()), User(Bob,List(User(Alice,List()))), User(Charles,List(User(Bob,List(User(Alice,List())))))) 注目してほしいのは parents という他のユーザを参照するリストを保持してることだ。 次に、users リストを JSON に変換したいとする。 [{ "name": "Alice", "parents": [] }, { "name": "Bob", "parents": [{ "name": "Alice", "parents": [] }] }, { "name": "Charles", "parents": [{ "name": "Bob", "parents": [{ "name": "Alice", "parents": [] }] }] }] この方法だと複数の問題点がある。まず、JSON の表記として効率が悪いし JSON データとして期待される自然な感じではないことだ。次に、これを case class に変換しなおしたときにオブジェクトのグラフごとインスタンス化する必要があって、それも非効率だし、望ましくない状況が多いと思う。sjson-new とアズカバンの囚人
本稿は sjson-new に関する第3部だ。パート1、パート2も是非読んでみてほしい。 sbt のコード内にはデータ永続化が数百メガバイトのオーダーに達している部分がいくつかあって、特にマシンに SSD が積まれていない場合は性能ボトルネックになる疑いがあるんじゃないかと思っている。 当然、最初に飛びついたのは Google Protocol Buffers のエンコーディングを参考に独自のバイナリフォーマットを実装することだった。 sbt-jmh を用いたマイクロベンチマーク 僕がまずやるべきだったのは、ベンチマークを取ることだ。@ktosopl (Konrad Malawski)君の sbt-jmh を使うとマイクロベンチマークは簡単に作ることができる。ビルドにプラグインを入れて、JmhPlugin を有効化したサブプロジェクトを定義するだけだ。 lazy val benchmark = (project in file("benchmark")). dependsOn(supportSpray). // add other subprojects you want to test enablePlugins(JmhPlugin). settings( libraryDependencies ++= Seq(jawnSpray, lm), // sbt-jmh forks the run, so you would need these javaOptions in (Jmh, run) ++= Seq("-Xmx1G", "-Dfile.encoding=UTF8"), publish := {}, publishLocal := {}, PgpKeys.publishSigned := {} ) 一つ注意が必要なのは sbt-jmh はフォークした run を使っているので、javaOptions in (Jmh, run) の設定が必要なことだ。sjson-new と LList を用いたカスタムコーデック
2ヶ月ぐらい前に sjson-new について書いた。週末にまたちょっといじってみたので、ここに報告する。 前回は Scala エコシステムにおける JSON ライブラリの家系をたどって、複数バックエンドに対応し、かつ型クラスベースの JSON コーデックライブラリという概念を導入した。課題は、カスタムコーデックを簡単に定義できるようにする必要があるということだった。 私家版 shapeless 4月に書いたのと先週までの間に flatMap(Oslo) 2016 と Scala Days New York 2016 という 2つのカンファレンスがあった。残念ながら、僕は flatMap の方には行けなかったけども、Daniel Spiewak さんの “Roll Your Own Shapeless” (「私家版 Shapeless のすゝめ」) というトークを New York で聞けた。flatMap 版の方が完全版でそれは vimeo にも出てるので、是非チェックしてみてほしい。 sbt の内部では、sbinary を用いたキャッシングに HList が用いられてたりする: implicit def mavenCacheToHL = (m: MavenCache) => m.name :*: m.rootFile.getAbsolutePath :*: HNil implicit def mavenRToHL = (m: MavenRepository) => m.name :*: m.root :*: HNil .foundweekends
週末に趣味プログラミングをする人のための Github organization として foundweekends を作った。参加したい人は twitter か Gitter で声をかけてください。
sjson-new
背景 ソフトウェアプロジェクトを考える面白い方法の一つとして、文学的な解析があると思う。つまり、実際のコードの字面を追うだけじゃなくて、誰が、いつ、何故 (どういった問題を解決するために) どのようにして (何の影響を受けて) 書いたのかを考察することだ。そういった意味では、Scala エコシステムにおいては JSON ライブラリほど豊かなジャンルは他に無いのではないだろうか。 2008年12月に Programming in Scala の初版が出て、JSON はパーサ・コンビネータの一例として出てきて、JSON パーサが 10行ぐらいのコードで書けることを示した: import scala.util.parsing.combinator._ class JSON extends JavaTokenParsers { def value : Parser[Any] = obj | arr | stringLiteral | floatingPointNumber | "null" | "true" | "false" def obj : Parser[Any] = "{"~repsep(member, ",")~"}" def arr : Parser[Any] = "["~repsep(value, ",")~"]" def member: Parser[Any] = stringLiteral~":"~value } 同年の一ヶ月前に Real World Haskell という本も出てて、これも JSON ライブラリを例をして使った (Chapter 5.sbt server リブート
これは先日書いた sbt 1.0 ロードマップの続編だ。この記事では sbt server の新しい実装を紹介する。感想やコメントがあれば sbt-dev mailing list にお願いします。
sbt server の動機は IDE との統合の改善だ。
ビルドは、巨大で、可変で、共有された、状態のデバイスだ。ディスクのことだよ! ビルドはディスク上で動作するのもであって、ディスクから逃れることはできない。
– Josh Suereth、The road to sbt 1.0 is paved with server より
マシンに積んであるディスクは根本的にステートフルなものであり、sbt がタスクを並行実行できるのもそれが作用に関する完全なコントロールを持っていることが大前提になっている。同じビルドに対して sbt と IDE を同時に実行していたり、複数の sbt インスタンスを実行している場合は、sbt はビルドの状態に関して一切保証することができない。
sbt 1.0 ロードマップ
sbt 1.0 にに関して TL上とかで議論があったので、叩き台としてこれを書くことにした。何かをちゃんとリリースできるように仕切り直しするための中期的なミッション・ステートメントだと思ってほしい。sbt-dev mailing list にて今後も議論を続けていきたい。 タイミング いつ sbt 1.0 をリリースできるかという予定はまだ見当が付いていない。 sbt 1.0 の最大の機能はコードの再組織で、それは既に進んでいる: http://www.scala-sbt.org/0.13/docs/Modularization.html sbt/io、 sbt/util、 sbt/librarymanagement、 sbt/incrementalcompiler といったモジュールがある。実装という観点からするとインクリメンタルコンパイラが sbt の中で一番複雑な部分だと思うので、まずはそれをモジュール化することを目標としてきた。全部のモジュールの API が安定したときが、sbt 本体にも 1.0 を付けれる時になる。 モジュール化の動機 sbt/sbt の現在のコードは、ビルドユーザやプラグイン作者に内部を晒しすぎている。これによってとっつきづらいコードになっている。さらに、バイナリ互換性を保つのも難しくなっている。 モジュール化の目標はどこまでが public な API でどこからが private な実装なのかの境界をハッキリさせることだ。 あと、これらのモジュールは今まで使ってたような Ivy リポジトリじゃなくて Maven Central に乗せる。 sbt/zinc 新しいインクリメンタルコンパイラは完全に name hashing に移行する。name hashing はしばらく前 (sbt 0.13.6) からデフォルトでオンになっている。それだけじゃなくて、クラスベースの name hashing を使う予定で、これは性能改善が期待されている。 Java バージョン sbt 0.13 は JDK 6 の上に書かれている。sbt 1.0 は JDK 8 ベースだ。ライフスタイルとしての ScalaMatsuri
僕にとって ScalaMatsuri とはライフスタイルのようなものだ (他の 27名近くいるオーガナイザーも同じように思っているんじゃないだろうか)。確かに、近日東京で 550名を動員したカンファレンスがあって、それは成功に終わった。しかし、オーガナイザーは 2015年の 2/28 からかれこれ 11ヶ月間準備してきた。僕が関わったのは一部でしかないけども、ScalaMatsuri 2016 はこれまでで一番関わりの深いカンファレンスになったと思う。この何ヶ月の間 Slack、Hangout たまには対面で、さまざまな議論を重ねてきた。面白かったのは、一緒にアイディアを出し合ってそれが実現されるのをみることだったと思う。僕が奇抜なアイディアを出して、その詳細を誰かが実行してくれることもあれば、他の人が始めたことを元に僕が現場の作業をすることもあった。 色々言いたいことは「グローバルな技術カンファレンス」と「日本のコミュニティの交流」の両立でも書いちゃったので、かぶる部分もあると思う。 2015年3月 2015年の 3/16 の段階で既に ScalaMatsuri 2015 の準備は回り始めていた。何故覚えているかというとそれは麻植さん (@oe_uia) が法被を来て Scala Days San Francisco に登場したからだ。カンファレンスと一緒にスキーやスノボもできるようにということで、あの場の雰囲気で 2016年の 1月にずらそうというアイディアが生まれた。 ホテル街は Scala Days の会場から少し歩く所にあってその帰り道で麻植さんと CFP を公開して固定費で旅費サポートを付けようという話をしたのを覚えている。これは少なくとも 2014年 (カンファレンスでのユニバーサル・アクセスへ向けて) ぐらいから考えてるアイディアで、非公開で誰かを招待してその人達の旅費を払うのに比べていくつもの利点があると思っている。カンファレンスを延期したことで以前より長い準備期間を得ることができたので、やってみる見込みがたった。 Github issue all the things 今回から以前のカンファレンス準備で使われていた Trello や co-meeting から Slack と Github issue の組み合わせに乗り換えた。 両者はそれぞれを補完する関係にあって、よい決断だったと思う。ラベルを使って issue を担当チームに割り当てるという運用をしていて、これもうまくいっていたと思う。 小さいタスクが大量にできてきて Github issue で困ったのは、特定のタスクが今どういう状況にあるのかを把握するのが難しいということだった。何かが起こるのを待っているのか、もしくは誰かが作業中なのか、といったことだ。issue の subject に括弧書きでミニ・ステータスを書くということをやってみたけども、翻訳タスクなど事前に明確にステップが定義されているタスク類に関してはこの括弧書き方式はうまくいったと思う。 「和」を想起させる web サイト 準備の早期の段階ではオーガナイザーは月一ぐらいのペースで会っていたと思う。僕を含め東京に住んでない人もいるので、ミーティングは Google Hangout でストリームされて、Hangout もしくは Slack 経由で議論に参加できた。「グローバルな技術カンファレンス」と「日本のコミュニティの交流」の両立
ScalaMatsuri 運営ブログに「グローバルな技術カンファレンス」と「日本のコミュニティの交流」の両立を書きました。
-Yno-lub を用いた Scala の厳格化
Scala は柔軟なプログラミング言語なので、個人的な Good Parts のような言語のサブセット、もしくは主義主張のあるスタイルガイドを作ることは有用だ。 セットアップ -Yno-lub を試してみたい人は、以下を project/ynolub.sbt に書いて sbt プラグインを引っ張ってくる: addSbtPlugin("com.eed3si9n" % "sbt-ynolub" % "0.2.0") lub Scala の型推論が型 A と型 B を統合するとき、それらの <:< に関する lub (least upper bounds, 最小上界) を計算する。この過程を lubbing と呼ぶこともある。具体例で説明する: scala> if (true) Some(1) else None res0: Option[Int] = Some(1) scala> if (true) List(1) else Nil res1: List[Int] = List(1) ここ数年考えているのは、少なくとも今ある形での lubbing は有益ではないのではないか、ということだ。2013年にもこんなことを言っている: are non-imported implicits and lubing useful in #scala? Map to List[Tuple2], Int to Double, Foo and Bar to Any.猫番: 1日目
猫番という新しいシリーズを始めた。(これは最初から Pamflet で書いている)
Cats は Scala のための関数型プログラミングのライブラリで、これは僕がそれを使ってみた記録だ。 Cats は、現在開発中で未だ実験段階にある。
Java バージョンの切り替え
最近 Mac と Ubuntu、それから Java 6 と Java 7 を行ったり来たりしてる。 Java の切り替え方を統一したいので、ここにメモしておく。 追記: jEnv という便利なものを Yoshida-san に教えてもらったので、それを使ったほうがいいかも。 Zshrc OS によるシェルスクリプトの切り替えはこんなふうにやってる: ## basic [ -f $HOME/dotfiles/zshrc.basic ] && source $HOME/dotfiles/zshrc.basic ## aliases [ -f $HOME/dotfiles/zshrc.alias ] && source $HOME/dotfiles/zshrc.alias case "${OSTYPE}" in # MacOSX darwin*) [ -f $HOME/dotfiles/zshrc.osx ] && source $HOME/dotfiles/zshrc.osx ;; # Linux linux*) [ -f $HOME/dotfiles/zshrc.linux ] && source $HOME/dotfiles/zshrc.linux ;; esac ## color [ -f $HOME/dotfiles/zshrc.color ] && source $HOME/dotfiles/zshrc.Scala Pickling 0.10.0
pickling 0.10.0 として implicit.ly に投稿したものを訳しました。 最近コミッター権をもらいましたが、Pickling の 90% 以上は Eugene Burmako、Heather Miller、Philipp Haller によって書かれています。 Scala Pickling は、Scala のための自動シリアライゼーション・フレームワークで、0.10.0 が初の安定版となる。Pickling は高速で、ボイラープレート (冗長なお決まりコード) 無しで書くことができ、ユーザ側で (バイナリや JSON などの) シリアライゼーション・フォーマットを簡単に差し替えることができる。また、0.10.x シリーズ中はバイナリ互換性とフォーマットの互換性の両方を保つ予定だ。 Pickling を短くまとめると ある任意の値、例えば Person("foo", 20) を pickle する (シリアライズ化を保存食に喩えて、漬物に「漬ける」と言う) とき、以下の 2つのものが必要になる: 与えられた型 Person の pickler コンビネータ pickle フォーマット Pickler[A] は A をエントリー、フィールド、コレクションといった抽象的なものに分解することを担当する。プリミティブな pickler を合成して複合的な pickler を作ることができるため、コンビネータと呼ばれている。一方 PickleFormat はフィールドなどの抽象的な概念をバイナリやテキストといった形に具現化する。 Defaults モード 以下は基本形である Defaults モードの使用例だ。 scala> import scala.pickling.Defaults._, scala.pickling.json._ scala> case class Person(name: String, age: Int) scala> val pkl = Person("foo", 20).モナドはフラクタルだ
Uppsala から帰ってくる途中、何となく思い出したのは同僚とのモナドの直観についての会話で、僕は酷い説明をした気がする。色々考えているうちに、ちょっとひらめきがあった。
モナドはフラクタルだ
上のフラクタルはシェルピンスキーの三角形と呼ばれるもので、僕がそらで描ける唯一のフラクタルだ。フラクタルとは自己相似的な構造で、上の三角形のように部分が全体の相似となっている (この場合は、親の三角形の半分のスケールの相似)。
モナドはフラクタルだ。モナディックなデータ構造があるとき、その値のいくつかを合成して同じデータ構造の新しい値を形成することができる。これがモナドがプログラミングに有用である理由であり、また多くの場面で登場する理由だ。
具体例で説明する:
scala> List(List(1), List(2, 3), List(4))
res0: List[List[Int]] = List(List(1), List(2, 3), List(4))
カンファレンスでのユニバーサル・アクセスへ向けて
2日間の #ScalaMatsuri は盛況に終わった。だけど、来年へ向けて色々課題もあるので、それを自分なりに書き出してみる。題の通り、僕達の次の目標とするべきものはユニバーサル・アクセスだと考えている。Scala 言語においては、統一アクセスの原則 (universal access principle) と言えば、メソッドとフィールドの両方が外側から見ると別けへだて無くアクセスできることを指す。 この文脈でのユニバーサル・アクセスは、様々なグループの人にとっても包括的 (inclusive) なカンファレンスという意味で使っている。具体的には: 女性/男性/ヘテロ/LGBT のプログラマ 日本語/英語話者 初心者と上級者 ポスドクなどの研究者 日本以外のアジア諸国からの人 など。 テクノロジー界における女性問題、及びその他のジェンダー問題 去年は女性によるセッション数はゼロ。今年は、マクロに関してのセッションが一つと、FuRyu さんのスポンサー LT が一本あった。これは良い傾向だと思うけど、僕としては、女性の人による Scala コミュニティ一般への参加、勉強会などへの出席、そして ScalaMatsuri のようなカンファレンスへの出席をもっと応援したいと思う。男性側としてできることの一つに、もし勉強会に参加してくれた女性の方がいたら、変な挙動を取らずに普通のハッカーの一人として接することがあると思う。 Scala Days、NE Scala、そして PNW Scala に倣って、今年の ScalaMatsuri では Geek Feminism Wiki/Ada Initiative を原案とする行動規範を採用した。この行動規範は、全員にハラスメント・フリーの経験を提供することを約束し、特に「全てのコミュニケーションは、技術的な発表の場にふさわしいものであるべき」ことを求める。今後、正式なハラスメント報告方法の確立などを含む、ポリシーの実装をはっきりさせる必要があるが、公的にこのようなガイドラインを採用できたことで、より inclusive なカンファレンスになっていくと考えている。 言語の壁 Scala がよく使われているその他の欧米諸国に比べて、日本の英語スキルは特にリスニングとスピーキングで遅れている。ScalaMatsuri の運営側としては、カンファレンスをより尖ったものにして、Scala コミュニティからより多くの英語話者を惹きつけることを目標の一つとしている。それに沿って、招待講演者の旅費を出したり、テキスト翻訳を提供したり、一般的に英語話者が来ても楽しめるように歓迎するようにしている。今年は、日本語話者でも英語で発表する人も出てきた。 このような努力は、Scala には興味があるが英語は苦手という多くのカンファレンス参加者にとって利害関係の衝突となる。リアルタイムで提供される有志によるテキスト翻訳は、無いよりはいいかもしれないけど、往々にして不十分である。解決方法として検討するべきはプロの通訳を雇うことだ。これは YAPC::Asia などではうまくいったらしい。さらに、2つの別路線 (track) を作って、それぞれ英語での発表と日本語での発表を行うべきだ。 初心者と上級者 Matsuri は祭という意味で、テーマも “enjoy Scala” だった。前から Scala をやってきてるユーザには確かに楽しいカンファレンスだったかもしれないが、僕のものも含め多くのトークは初心者を置いてきぼりにしたものとなった。この回避方法となり得るかもしれないのが、英語路線と日本語路線の区別の他に、NE Scala のようにセッションを参加者の投票で決めてもらうことだ。(通訳付きで)英語のセッションでも聞いてみたい人と上級者、逆に日本語にして欲しい人と初心者に相関性があると仮定すると、それぞれの路線が、投票によって聴衆が聞きたい適切なレベルに補正されるのではないだろうか。 ポスドクとアジア諸国からの参加者 1日目のレポートに書いたとおり、宋 剛秀さんの発表は唯一学術的な方面からのものだったけど、独自で面白いものだった。アメリカやヨーロッパからのロックスター的な登壇者を観るのも面白いけども、日本から宋さんのようなポスドクの研究者や、はたまた近隣のアジア諸国である、インド、中国、韓国、台湾、シンガポールなどから呼んでみるのも面白いのではないだろうか。英語路線を設けることで、日本語の心配はいらなくなると思う。実装する方法の一つとしては、CFP をもっと比較的長く取って、例えば最大 $1500 までで旅費のサポートをすると宣伝すればいいと思う。投票後には、旅費予算から差し引いていって、票の多い順に可能な限りの人を招待すればいい。 全ての受け皿としてのアンカンファレンス もし英語路線か日本語路線のどちらかの競争率が高くなっても、今後はアンカンファレンスを受け皿として機能させることができる。今回で多くの人が直接アンカンファレンスが行われる様子を見たので、今後はより多くの議論や準備済みのトークが増えることを期待していう。来年からはホワイトボードを廃止して、当日の朝に Google docs に直接全てのアンカンファレンスのアイディアをファシリテータ名と共に書く方向に変えていくべきだと思う。狙いはあまり人気が無いセッションでも部屋が空いていれば、ちゃんとセッションを設けることにある。ScalaMatsuri 1日目
日本での Scala カンファレンスも今年で二年目だ。今年は ScalaMatsuri と名前を変えて仕切り直し。300枚のチケットは売り切れ、招待講演者やスポンサー招待枠などを入れたら当日はもっといたかもしれない。アメーバブログやオンライン広告サービスなどを事業とする CyberAgent さんのオフィスを会場としてお借りした。 1日目のトップバッターは小田好先生こと Martin Odersky 先生 (@ordersky) の「Scala 進化論」。多くの人が小田好先生の講演を楽しみにしていたので、朝から満員に近かったと思う。僕が出席したセッションは、拙作の closed-captioning を使って和英、英和のテキスト翻訳を打ち込むのに忙しかった。一日目翻訳チームの他のメンバーは、@cbirchall、 @cdepillabout、 @okapies、 @oe_uia。 次に僕が「sbt、傾向と対策」を日本語で話した。mkdir helloworld から始めて、sbt の最初のステップから、continuous testing までの流れのデモから始めた。次に、基礎コンセプト、0.13.6 で入る新機能である HTTPS デフォルト、consolidated resolution、eviction warning を紹介して、最後に「サーバとしての sbt」とさらなる性能の改善という将来の展望でシメた。LinkedIn社のプレスチームから、LinkedIn が sbt の性能改善の仕事をスポンサーしてもらってることを話してもいい許可をもらってきたので、今回機能改善に関して公の場でお礼できたのは良かったと思う。 Activator と sbt に関して質問があった。Activator の 3つの用例ということで以下のように回答した: トレーニング・セッションなどにおける USBドライブなどによる Typesafe スタックのオフライン配布 新ユーザの out-of-the-box エクスペリエンス (箱を開けてすぐ遊べること) の改善 ユーザがコードを打ち込みながら使えるチュートリアルをホストするプラットフォーム sbt サーバに関しては、IntelliJ などの他のツールとの連携、と将来的な remote compilation などの可能性ができること両方について好反応を得た。 Jon Pretty (@propensive) さんの ‘Fifty Rapture One-Liners in Forty Minutes’ という講演。リソースの読み書きを抽象化することに焦点を絞ったライブラリみたいで、オンラインから色々読み込んで、生の状態の読み込み (slurp) や case class への落とし込みをするみたいだ。enrich-my-library、マクロ、dynamics などユーザ・フレンドリーな Json 処理のために言語のトリックを多用している。バックエンドの json ライブラリが選べるようになっているのは好印象。Vim メモ
個人的には SublimeText で特に困っていないし、メインのエディタとしてしばらく使ってきた。だけど、コマンドラインから使えるエディタにも少しは興味があるし、色んな人がネットワーク上から使えるから便利ということを言っている。X を転送したり、他の方法でリモートインすれば Sublime を使えるんじゃないかとも思うが、一応試してみよう。 この Vim のセットアップをしようと思ったキッカケの一つに新しく MBP を買ったというのがあって、折角だから何か新しいことをやってみようかなと思った。つまり、本稿は完全な素人が個人的なメモとして書いてあるものだ。そもそもブログというのはそういうものなはずだ。動くかどうかは保証できない。全般的に yuroyoko さんが数年前に書いた iTerm2 + zsh + tmux + vim で快適な256色ターミナル環境を構築するを参考にした。 Vim 以外の色々なこと dotfiles 本稿で書いたセットアップは eed3si9n/dotfiles に上げてある。他の人の dotfiles を fork するのが作法らしいけども、自分の環境に持ち込む設定をちゃんと理解したかったので、一から書き始めた。 dotfiles の基本的な考え方としては、これを ~/dotfiles/ にまず checkout して、そこには zshrc などのファイルが入ってる。これらのルートの設定ファイルはホームディレクトリ内で ~/.zshrc などという感じでシンボリックリンクが張られる。 Terminal.app Mac で iTerm2 がどうしても必要になったことはまだない。以前には Terminal.app に色々と制限があったのかもしれないけど、今の所僕はこれで間に合っている。 Terminal.app を使い続けている理由のもう一つが、僕が TotalTerminal のファンであることだ。 homebrew Homebrew にはお世話になっている。 Zsh このマシンのシェルは Zsh にする。Mac なら How to use Homebrew Zsh Instead of Max OS X Default を参照:Scala を用いたスクリプティング
現実問題として正規表現が必要になることがある。いくつかのテキストファイルに変換をかけたりする度に find コマンド、zsh のドキュメントや Perl 関連の StackOverflow の質問を手探りしながら作業することになる。苦労しながら Perl を書くよりは Scala を使いたい。結局、僕個人の慣れの問題だ。 例えば、今手元に 100以上の reStructuredText ファイルがあって、それを markdown に変換する必要がある。まずは pandoc を試してみて、それはそれなりにうまくいった。だけど、中身をよく読んでみるとコードリテラルの多くがちゃんとフォーマットされてないことに気づいた。これは単一のバッククォート (backtick) で囲まれていたり、Interpreted Text を使っているからみたいだ。このテキストをいくつかの正規表現で前処理してやればうまくと思う。 コマンドライン scalas 僕の現在の開発マシンには scala へのパスが通っていない。zip ファイルを一回ダウンロードするのは大した作業じゃないけども、将来的に jar とスクリプトの管理をしなきゃいけないのが面倒な気がする。普通なら僕は sbt を使って Scala の jar をダウンロードさせる。それでもいいけども、単一のファイルのみを使った解法が欲しいとする。 そこで今試してるのが sbt の script runnerだ: #!/usr/bin/env sbt -Dsbt.version=1.4.7 -Dsbt.main.class=sbt.ScriptMain -Dsbt.supershell=false -error /*** ThisBuild / scalaVersion := "2.13.4" */ println("hello") 次に、 $ chmod +x script.scala $ ./script.scala hello これで自分の Scala version を 2.13.4 に指定するスクリプトができた。コンパイルを含めて “hello” が表示されるまで 8秒かかるから、サクサクとは程遠い感じだけど、個人的には許容範囲内だと思う。sbt テクノロジ・プリビュー: auto plugin
Preview of upcoming sbt 1.0 features: Read about the new plugins を訳しました。 著 @eed3s9n, @jsuereth sbt に変化が訪れようとしている。sbt 1.0 へ向けて sbt の原理である自動化 (automation)、インタラクション (interaction)、統合化 (integration) の全面において改善がみられる予定だ。1.0 の二大機能と目されているのは auto plugin と「ビルドサーバとしての sbt」の 2つだ。 今後の数ヶ月にわたって sbt チームは sbt 0.13 コードベース上にこれらの機能を追加したプリビュー版をリリースする。これらのプリビュー版によって、sbt 1.0 の仕様が固まる前にコミュニティーからのフィードバックを得たり、新しい設計方針や理念そして新機能を促進することを目的としている。 長い間 sbt を支えてきた Mark Harrah がビルド以外のことをするために旅立っていったことを残念ながら報告しなければならない。しかし、Typesafe のビルドツールチームである Antonio Cunei、Josh Suereth に新たなメンバー Eugene Yokota (@eed3si9n) が sbt の techlonogy lead の一人として参加することを歓迎したい。 本稿では、今回できあがった auto plugin 機能を紹介する。これは sbt 0.13.5-M2 リリースに含まれる。 プラグイン・エコシステム sbt の最大の強みとしてプラグイン・エコシステムを挙げることができる。プラグインはビルド定義と全く同じように動くため、sbt を習うことはそのままプラグインを書くのを習うことにつながっていく。sbt プラグインの多様性はこの基本的なコンセプトの力強さを物語っているだろう。中でも Play Framework と Activator の二つは抜き出ている。これらは sbt の上にで作られていてインタラクティブな開発エクスペリエンスを提供しているからだ。Scala でのクラス線形化 (mixin 順序) の制約
昨日は、何故か早朝に目が覚めて @xuwei_k氏のScalaで抽象メソッドをoverrideする際にoverride修飾子を付けるべきかどうかの是非を流し読みしていた。この話題は面白すぎたので、飛び起きてすぐに英訳してしまった。Scalaz で遭遇したコードを例にして型クラスのデフォルトインスタンスを提供することの微妙なジレンマを解説している。 以下に問題を簡略化したコード例を示す: trait Functor { def map: String } trait Traverse extends Functor { override def map: String = "meh" } sealed trait OneOrFunctor extends Functor { override def map: String = "better" } sealed trait OneOrTraverse extends OneOrFunctor with Traverse { } object OneOr { def OneOrFunctor: Functor = new OneOrFunctor {} def OneOrTraverse: Traverse = new OneOrTraverse {} } これをテストするには以下を実行する: scala> OneOr.OneOrTraverse.map res0: String = meh OneOr.sbt-sequential を用いたタスクの逐次化
本稿では sbt 0.13 における実行意味論 (execution semantics) とタスクの逐次化 (task sequencing) についてみていこうと思う。まずは前提となる背景を大まかに復習して、次に逐次的タスク (sequential task) を追加するために書いた実験的プラグイン sbt-sequential を紹介したい。 背景 Mark 曰く: sbt のモデルは副作用をタスクに局所化させることで、依存性さえ満たせば、タスクはいつでも実行できるというものだ。この利点はデフォルトで並列であることで、実際により速いビルドを可能とすることだ。 言い替えると、sbt を使ったビルド定義はタスク間の依存性のみを定義していて、これらのタスクがどのタイミングで始動されるかは sbt によって自動的に計算される。これをちゃんと理解するために、まず副作用を持った Scala コードの実行意味論をみてみよう。 直列実行 (serial execution) class Test { def startServer(): Unit = { println("starting...") Thread.sleep(500) } def stopServer(): Unit = { println("stopping...") Thread.sleep(500) } def numberTask: Int = 1 def integrationTest0(): Int = { val n = numberTask startServer() println("testing...") Thread.sleep(1000) stopServer() n } } 誰かが integrationTest0() を呼び出すと、コードは書かれたのと全く同じ順序で実行される。まず numberTask が呼び出され、次に startServer() が呼ばれこの実行は 0.Spire の Ops マクロ: 暗黙の演算子の高速化
一見普通の演算でもいかに高速化できるかをいつも考えて発表してる奇才 Eiríkr Åsheim (@d6) さんの “How to use Spire’s Ops macros in your own project” を翻訳しました。いつも気さくに話しかけてくれるフレンドリーでいいやつです。翻訳の公開は本人より許諾済みです。 2013年10月13日 Eiríkr Åsheim 著 2013年11月20日 e.e d3si9n 訳 Spire の Ops マクロとは何か? Spire の型クラスは + や * といった基礎的な演算子を抽象化する。普通これらの演算は非常に速い。そのため、ちょっとでも余計な事 (例えば、boxing やオブジェクトの割り当てなど) を演算ごとにやってしまうと、ジェネリック化したコードは直接呼び出したものと比べて遅いものになってしまう。 効率的かつジェネリックな数値プログラミングが Spire の存在意義だ。不必要なオブジェクト割り当てを回避するために僕たちはいくつかの Ops マクロを用意した。本稿ではその仕組みと、君のコードからそれらのマクロを使う方法を解説する。 通常の型クラスを用いた暗黙の演算子の仕組み Scala で型クラスを用いる場合、通常は暗黙の変換に頼ることでジェネリックな型に演算子を「追加」する。(訳注: いわゆる Enrich my library パターンだ) 以下に具体例で説明すると、A はジェネリックな型、Ordering は型クラスで、> が暗黙の演算子となる。foo1 はプログラマが書くコードで、foo4 は implicit が解決されて、糖衣構文が展開された後のものだ。 import scala.math.Ordering import Ordering.Implicits._ def foo1[A: Ordering](x: A, y: A): A = x > y def foo2[A](x: A, y: A)(implicit ev: Ordering[A]): A = x > y def foo3[A](x: A, y: A)(implicit ev: Ordering[A]): A = infixOrderingOps[A](x)(ev) > y def foo4[A](x: A, y: A)(implicit ev: Ordering[A]): A = new ev.sbt 0.13 を用いた四次元空間内の移動
警告: この sbt についての覚え書きは中級ユーザ向けだ。 セッティングシステム sbt 0.12 同様に sbt 0.13 の中心にあるのはセッティングシステムだ。Settings.scala を見てみよう: trait Init[Scope] { ... final case class ScopedKey[T]( scope: Scope, key: AttributeKey[T]) extends KeyedInitialize[T] { ... } sealed trait Initialize[T] { def dependencies: Seq[ScopedKey[_]] def evaluate(map: Settings[Scope]): T ... } sealed class Setting[T] private[Init]( val key: ScopedKey[T], val init: Initialize[T], val pos: SourcePosition) extends SettingsDefinition { ... } } pos を無視すると、型 T のセッティングは、型が ScopedKey[T] である左辺項 key と型が Initialize[T] である右辺項 init によって構成される。オブジェクト指向プログラミングとは何か?
oop はどう定義されるべきだろうか?
純粋オブジェクト指向プログラミング
純粋オブジェクト指向プログラミングは以下のように定義できる:
オブジェクトを使ったプログラミング。
オブジェクトとは何か?
他のオブジェクトへの参照を保持し、事前にリストアップされたメッセージを受信することができ、他のオブジェクトや自分自身にメッセージを送信することができるアトムで、他には何もしない。メッセージは名前とオブジェクトへの参照のリストから構成される。
これでおしまい。言い回しは僕が考えたものだけど、アイディアはオブジェクト指向という言葉を作った張本人 Alan Kay (2003) からのものだ。これ以外は、直接 oop に関係無いか、実装上の詳細だ。
sbt 0.13.0 の変更点
概要 互換性に影響のある新機能、変更点、バグ修正 sbt とビルド定義を Scala 2.10 に移行した。 project/plugins/ 内に置かれたプラグインの設定ファイルのサポートを廃止した。これは 0.11.2 より廃止予定になっていた。 set コマンドにおいてセッティングの右辺項内のタブ補完を廃止した。新たに追加されたタスクマクロがこのタブ補完を不要にするからだ。 キーの慣用的な書き方はこれよりキャメルケース camelCase のみとする。詳細は後ほど。 Maven との互換性を正すため、テストのデフォルトの classifier を tests に修正した。 グローバルなセッティングとプラグインのディレクトリをバージョン付けるようにした。デフォルトでは、グローバルセッティングは ~/.sbt/0.13/ に、グローバルプラグインは ~/.sbt/0.13/plugins/ に置かれる。sbt.global.base システムプロパティを使った明示的なオーバーライドは継続して適用される。(#735) scalac にファイルを渡すときに sbt が行なっていた正規化 (canonicalization) を廃止した。(#723) 各プロジェクトがそれぞれ固有の target ディレクトリを持つことを強制するようにした。 依存ライブラリの Scala バージョンをオーバーライドしないようにした。これによって個別の設定が異なる Scala バージョンに依存できるようになり、scala-library 以外の Scala 依存性を通常のライブラリ依存性と同じように扱えるようになった。しかし、これによってその他の scala-library 以外の Scala ライブラリが最終的に scalaVersion 以外のバージョンに解決される可能性も生まれた。 Cygwin での JLine の設定が変更された。Setup 参照。 Windows 上での JLine と Ansi コードの振る舞いが改善された。CI サーバ内では -Dsbt.log.format=false を指定して明示的に Ansi コードを無効にする必要があるかもしれない。 フォークされたテストや run がプロジェクトのベースディレクトリをカレント・ワーキング・ディレクトリとして用いるようにした。 compileInputs は Compile ではなく (Compile,compile) 内で定義するようにした。 テストの実行結果は Tests.シンプルさの必要性
2012年4月23日にテキサスの Austin で行われた RailsConf 2012 での Rich Hickey (@richhickey) さんによる基調講演、Simplicity Matters を書き起こして翻訳しました。 Rich Hickey さんは Clojure や Datomic の作者です。 この翻訳は Creative Commons Attribution ShareAlike 3.0 ライセンスに基いて公開します。
Rich Hickey 講演 e.e d3si9n 訳
Scala: 空飛ぶサンドイッチのパーツ
JavaScript が作られたのは 1995年のことだから、『JavaScript: The Good Parts』(2008年)、jQuery (2006年)、V8 (2008年) などが登場するよりもかなり前に作られたことになる。jQuery と V8 が加算的な貢献であるのに対して、Douglas Crockford 氏の『The Good Parts』が面白いのは、言語から機能を引き算した本であることだと思う。 ここ最近、もし Scala をリアルワールドな制約である Java 的な親しみやすさや互換性を無視してワンダーランド的な設定でサブセットを作ったらどうなるだろうかと考えている。Scala を Java の代替として使う事が許されるなら、関数型プログラミング言語の代替として使ってもいいじゃないかと思う。この思考実験のもう一つの試みは、Scala の構文の中で重複しているものを減らすことだ。本稿では、慣用的な用法が何かを考えたり、何かに対して良し悪しの判定を下すことには興味は無い。これは空飛ぶサンドイッチのパーツ (The Flying Sandwich Parts; TFSP) と呼ぶことにする。 値 What talk you of the posy or the value? — William Shakespeare, Merchant of Venice Scala 言語仕様は値を以下のように定義する: 値定義 val x : T = e は、e の評価から得られる値の名前として x を定義します。 TFSP においては、トレイトやクラスの本文内では型注釈 T の省略を禁止する。関数内のローカルの値は型推論を使って定義してもよい。これによって関数レベルにおいて型検査が行われることが保証される。 遅延評価値 素の val を使って値を定義すると、定義した順番に気を使う必要がある。初期化する前に値を参照してしまうと実行時に NullPointerException が発生してしまう。値を lazy だと書くことで最初に参照されるまで初期化を遅延することができる。scopt 3.0
scopt is a little command line options parsing library. 今日 scopt 3.0 をリリースする。実装の詳細に興味が無ければ、readme に飛んでほしい。 2010年3月4日ごろ僕は scopt のコミッタになった。これは元々 Aaron Harnly さんが 2008年ごろ書いた scala-options のフォークだ。確か、usage text 周りの変更と key=value options と argument list という機能を追加したかったんだと思う。それ以降全てのバグレポを担当してきた。その中には jar を scala-tools.org に公開してくれというのもあった。2012年3月18日、僕は再びプロジェクトを scopt/scopt にフォークして immutable parser を追加した scopt 2.0.0 をリリースした。 数年に渡って重ねるようにして機能が追加されたため、scopt3 は一から書き直すことにした。発端となったのは Leif Wickland さんに「scopt に intArg() が無いのは設計上の理由があるのか」と聞かれたことだ。 Ruby の OptionParser に inspire されて書かれた元の Aaron さんの scala-options にはオプションのために 5個のメソッドがあった: onInt、 onDouble、 onBoolean、 on、それからもう一つオーバーロードされた on。重なる開発の結果 scopt2 は opt のオーバーロードが 6つ、intOpt、 doubleOpt、 booleanOpt、 keyValueOpt、 keyIntValueOpt、 keyDoubleValueOpt、 keyBooleanValueOpt それぞれに 4つづつのオーバーロードが蓄積された。合計 34 ものメソッドだ!Dispatch プラグインの書き方
Dispatch は Scala からネットへつなぐデファクトの方法であり続けてきた。昨今のノンブロッキングIO への流れと歩調を合わせて @n8han はライブラリを Async Http Clientベースのものに書きなおし、Reboot と呼んだ。後にこれは、Dispatch 0.9 としてリリースされる。さらに、独自の Promise を SIP-14 で標準化された Future に置き換えたものが Dispatch 0.10 だ。 Dispatch Classic 同様に Reboot でも web API をラッピングしたプラグインを作ることができる。本稿では、Classic で書かれたプラグインを移植しながら Dispatch 0.10 プラグインの書き方を解説していく。 repatch-twitter 他のプラグインとの名前の衝突を回避するために、僕のは dispatch-twitter ではなく repatch-twitter と呼ぶことにする。 sbt まずは sbt の設定から始める: repatch-twitter/ +- project/ | +- build.properties | +- build.scala +- core/ +- src/ +- main/ +- scala/ +- requests.scala +- ... build.properties の中身: sbt.version=0.12.3 build.scala の中身:カンファレンスを翻訳する
もう一ヶ月経つけど 2013年3月1日に日本に一時帰国して「Scala Conference in Japan 2013」に出席した。そういう名前のカンファレンス。 ポッドキャストから ある日 (2012年6月2日だけど) Scala Days 2012 で録音された Scala Types を聞いていると誰かが (@timperrett さん) “I would love to see Scala Days in Asia. We had two in Europe now. It would be wicked to have it in China or Japan, or somewhere like that.” と言っていたので、その趣旨を Twitter で伝えた: 今 Scala Days 2012 で録音された Scala Types を聴いてたら、開催地が欧米圏に偏ってるから次あたり日本とかアジア圏なんてどうだろうって話が出てた。コミュニティが声出せば誘致もありえるかも 会話が始まると @jsuereth がすぐに支持の声を上げてくれた: @kmizu @eed3si9n_ja If you guys manage to get a Scala conference somewhere in asia, I’ll be there!抽象的な Future
これは Scalaz Advent Calendar 2012 12日目の記事です。 次々と Scala 界の知能派を集結させている Precog 社の開発チームからのブログ Precog.Copointed。今日は blueeyes などの開発でも知られる Kris Nuttycombe (@nuttycom) さんが書いた The Abstract Future を翻訳しました。翻訳の公開は本人より許諾済みです。 2012年11月27日 Kris Nuttycombe 著 2012年12月11日 e.e d3si9n 訳 Precog 開発ブログの前回は僕たちが Cake パターンを使ってコードベースを構造化して、ギリギリまで実装型を抽象化してしていることを Daniel が書いた。その記事での説明のとおり、これは非常に強力な概念だ。型を存在型として保つことで、やがて選択された型を「意識」していないモジュールからはそれらの型の値は不可視であるため、カプセル化の境界の突破をコンパイラが防止してくれる。 今日の記事では、この概念を型からさらに進めて型コンストラクタに適用して、計算モデルを丸ごと置き換える機構として使えることを説明する。 Scala を少しでも使ったことがあれば、何らかの文脈で誰かが「モナド」という言葉を使ったのを聞いたことがあるだろう。例えば、Scala の for というキーワードにより提供される糖衣構文に関する議論か、Option 型を使うことで null 参照エラーの落とし穴が回避できることを説明したブログ記事で読んだのかもしれない。Scala でのモナドに関する議論の大半が「コンテナ」型に焦点を当てているのに対して、Scala エコシステムでよく見かけるいくつかの型の中にモナディック合成のより面白い側面が表れるものがある。限定計算 (delimited computation) だ。どのモナディックな型を合成してもこの側面を見ることができるが、これを直接利用した例として最もよく使われている Scala でのモナディックな型に非同期計算をエンコードした akka.dispatch.Future がある (これは Scala 2.10 において現行の Future を置き換える予定のものだ)。これは計算のステップを順序付けするための柔軟な方法を提供することで、本稿が注目するモナディック合成の一面を体現する。 ここで一言断っておくが、この記事はモナドのチュートリアルとして機能することを意図していない。モナドの解説とその Scala のプログラミングとの関連を取り扱った記事は既にたくさんある (ありすぎるかも!)。もしこの概念に不慣れなら読み進める前にそれらの解説を読むと役に立つかもしれない。しかし、最初に注意しておきたい点が一つあって、(モナディック合成のための糖衣構文としての for が示すとおり) Scala ではモナドは広い範囲で利用されているにも関わらず Scala の標準ライブラリに Monad 型が無いというのは Scala 固有な状況だということだ。そのため、モナド型が必要ならば標準ライブラリ外の素晴らしい Scalaz プロジェクトを使う。Scalaz のモナド抽象体は implicit 型クラスパターンを利用している。以下にベースの Monad 型を簡略化したものを示す:Func を使った数独
これは Scalaz Advent Calendar 2012 5日目の記事です。 12月の間中、日本の技術系ギークは日替わりでテーマに沿った記事を公開し、彼の国では「Advent Calendar」と呼ばれているらしい。去年の Scala Advent Calendar 2011 で僕は Eric Torreborre さんが The Essence of Iterator Pattern をカバーした記事を翻訳した。これは日本人の関数型プログラミング記事好きを知った上である程度狙ったものだった。もう1つの利己的な動機は、記事を一語一語訳す過程において概念のいくつかは僕の頭にも染みこんでくれるんじゃないかという期待だった。振り返ってみると、両方の目的とも作戦成功だったと言える。Jeremy Gibbons さん、Bruno Oliveira さんそして Eric 両方の仕事のクオリティのお陰だ。これらの染み込んだ知識が今年に書いた独習 Scalaz シリーズの隠し味だったんじゃないかと思っている。 独習 Scalaz 12日目でふれたとおり、Scalaz 7 の型クラスインスタンスには既に product と compose が含まれており、また Traverse も定義されている。論文にある word count の例題 まである。僕が気づいたのは、値レベルでの合成が無いことだ。この論文の興味深い点の1つに「applicative functor の合成」があり、これはモジュール化プログラミング的なものを可能とする。 Gibbons と Oliveira の言う「applicative functor」は実は型クラスのインスタンスだけではなく、applicative 関数の合成も指している。これは論文からの以下の抜粋をみれば明らかだ: data (m ⊠ n) a = Prod { pfst :: m a, psnd :: n a } (⊗) :: (Functor m, Functor n) ⇒ (a → m b) → (a → n b) → (a → (m ⊠ n) b) (f ⊗ g) x = Prod(f x)(gx) 代数データ型の ⊠ は型レベルの積だが、中置関数の ⊗ は 2つの applicative 関数の値レベルの積で、a → (m ⊠ n) という型の applicative 関数を返す。言い換えると、プログラマは applicative functor を返す関数を構築するだけよくて、型レベルでの合成は自動的に行われる。絵で見るモナド
John Wiegley さんの “Monads in Pictures” を翻訳しました。翻訳の公開は本人より許諾済みです。翻訳の間違い等があれば遠慮なくご指摘ください。
2012年8月20日 John Wiegley 著 2012年8月21日 e.e d3si9n 訳
これはモナドのチュートリアルではないし、ここには数学用語も出てこない。本稿は、既にモナドを一応使えるぐらいには習った人を対象とする。視覚化することで、何のために何をやっているかが明らかになるはずだ。
関数
モナドに対する直感を得る一つの方法として関数からモナドへの抽象化をたどるというものがある。関数が何をやっているのかを簡単な絵で表してみよう。Haskell の関数の呼び出しの構文を上に、同じ演算を視覚化したものを下に置いた:

Scala 2.10 におけるメタプログラミング: 構文木、シンボル、型について
Scala マクロの作者 Eugene Burmako さんによるリフレクション API に関する発表のスライド、“Metaprogramming in Scala 2.10” を翻訳しました。翻訳の公開は本人より許諾済みです。翻訳の間違い等があれば遠慮なくご指摘ください。 2012年4月28日 Eugene Burmako 著 2012年8月5日 e.e d3si9n 訳 はじめに メタプログラミング メタプログラミングとは、他のプログラムや自身をデータとして書いたり操作するコンピュータプログラムを書くこと。 —Wikipedia コンパイラ 問: どうやってメタプログラミングを可能にすることができだろう? 答: コンパイラよりもプログラムに関してデータを持つ者がいるだろうか? プログラマにコンパイラを公開しよう。 リフレクション 2.10 ではプログラムに関するデータをリフレクション API として公開する。 この API は、scala-library.jar (インターフェイス)、scala-reflect.jar (実装)、scala-compiler.jar (実行時コンパイル) にまたがっている。 Martin の方が詳しい 先日行われた Martin Odersky 先生による講演にてリフレクション API の設計が詳しく説明されている: http://channel9.msdn.com/Events/Lang-NEXT/Lang-NEXT-2012/Reflection-and-Compilers 実習 今日は、いくつかの具体例を通してリフレクション API の基礎を習い、またどうやって更に多くの情報を得られるかを習う。 マクロ 問: ちょっと! マクロはどうなってるの? 答: マクロの核となるのはリフレクションであり、リフレクションがマクロを API として提供し、リフレクションがマクロを可能とする。今日はまずリフレクションを理解することに焦点を当てる。マクロは小さな後付けにすぎない。 マクロ、その哲学と応用に関しては、Scala Days での講演を参考にしてほしい: http://eed3si9n.com/ja/scala-macros-scaladays2012 リフレクション コアとなるデータ構造 構文木 (Tree) シンボル (Symbol) 型 (Type) $ scalac -Xshow-phases phase name id description ---------- -- ----------- parser 1 ソースを AST へとパースし、簡単な糖衣構文展開 (desugaring) を行う。 namer 2 名前を解決し、シンボルを名前付けされた構文木へと関連付ける。 typer 4 メインコース: 構文木を型付けする。 pickler 7 シンボルテーブルをシリアライズする。 できる限り分かりやすくこれらの概念の説明をするつもりだが、Paul Phillips 以上の説明は恐らく誰にもできない。 Inside the Sausage Factory という講演は絶対に見ておいたほうがいい。初めての Scala マクロ
Scala マクロの作者 Eugene Burmako さんが管理する scalamacros.org から “Getting started” を翻訳しました。翻訳の公開は本人より許諾済みです。翻訳の間違い等があれば遠慮なくご指摘ください。 Eugene Burmako 著 2012年7月31日 e.e d3si9n 訳 1. Scala 2.10 を入手する マクロは 2.10.0-M3 以降の Scala で出荷されている。現行のマイルストーンである 2.10.0-M6 などのマクロが入ったコンパイラを直接ダウンロードするか、Maven や sbt などから参照する。好きな方法を使っていい。 訳注: sbt 0.11.3 を使ったプロジェクトを github に用意したので、 git clone -b ja https://github.com/eed3si9n/scalamacros-getting-started.git でセットアップできる。 2. マクロを書く Macros.scala というファイルを作って以下のコードをペーストする (関連する API やインフラなどマクロシステムに大切なことが書かれているのでコメントもしっかり読んでほしい)。 import scala.reflect.makro.Context import collection.mutable.ListBuffer import collection.mutable.Stack object Macros { // マクロ定義のシグネチャは好きなパラメータを受け取る普通の関数と同じだ。 // しかし、本文は実装への参照のみとなる。 def printf(format: String, params: Any*): Unit = macro printf_impl // マクロ実装のシグネチャはマクロ定義のものと対応する必要がある。 // 一見複雑に見えるが、心配する必要はない。 // もしコンパイラが不満なら、エラーメッセージで必要なシグネチャを教えてくれる。 def printf_impl(c: Context)(format: c.Scala マクロ、ロンドンに現る
マクロの作者として今注目を浴びている Eugene Burmako さんと、マクロを使って言語統合されたデータベース接続行うライブラリ SLICK の作者である Jan Christopher Vogt さんが今年の Scala Days で行った発表のスライドを翻訳しました。翻訳の公開は本人より許諾済みです。翻訳の間違い等があれば遠慮なくご指摘ください。
2012年4月18日 Eugene Burmako、Jan Christopher Vogt 著 2012年7月30日 e.e d3si9n 訳
Scala マクロ
(頭をおかしくせずに) コンパイラを拡張する権限を開発者に与える!
これはコンパイル時に以下を行う:
- 検査
- 処理
- AST 変換
- コード生成
- ランタイムへの AST の配備
訳注: Scala マクロは 2.10 より導入されるコンパイル時にコードを置換する機構だ。これにより今までボイラープレートが必要だったものを自動生成できるようになるなど、より高い表現力を手にすることができる。
Scala脳のための C# LINQ
これは Scala プログラマのための C# LINQ 機能の覚え書きだが、逆としても使えるはず。 型推論 C# には型推論がある。個人的に、ローカル変数ではできるだけ var を使うようにしている。 var x = 1; Scala にも var があるけど、可能なら不変 (immutable) な val を使うのが好ましいとされている。 val x = 1 新しい List と Array の作成 C# はインラインでコレクションを作ることができる。 using System.Collections.Generic; var list = new List { “Adam”, “Alice”, “Bob”, “Charlie” }; var array = new [] { 0, 1, 2 }; 全ての Scala コレクションにファクトリメソッドがある。 val list = List("Adam", "Alice", "Bob", "Charlie") val array = Array(0, 1, 2) ラムダ式を使ったフィルタ C# には “enrich-my-library” 的なモンキーパッチングがあり、普通の Array に Where メソッドが追加されている。sbt 0.12.0 の変更点
ついに final がリリースされた、sbt 0.12.0 の変更点を訳しました。 バイナリバージョンという概念が導入されることで、Scala 2.9.0 で入ったけどあまり活用されていない Scala の後方バイナリ互換性がより正面に出てくるキッカケとなると思います。 互換性に影響のある新機能、バグ修正、その他の変更点 Scala 2.10 以降の Scala 及び sbt プラグインのクロスバージョン規約の変更。 (詳細は以下の項目 ) 直接実行された場合、強制的に update を実行するようにした。 #335 sbt プラグインリポジトリがプラグインとプラグインの定義にデフォルトで加わった。 #380 プラグイン設定ディレクトリの優先順位。 (詳細は以下の項目 ) ソース依存性の修正。 (詳細は以下の項目 ) 集約がより柔軟になった。 (詳細は以下の項目 ) タスク軸の構文が key(for task) から task::key へと変更された。 (詳細は以下の項目 ) sbt の organization が org.scala-sbt へと変更された。(元は、org.scala-tools.sbt) 特に、scripted プラグインのユーザはこの影響を受ける。 artifactName の型が (ScalaVersion, ModuleID, Artifact) => String となった。 javacOptions がタスクとなった。 session save は build.sbt 内の設定を(適切な時に)上書きするようにした。#369 新機能 テストのフォークのサポート。 #415 test-quick。 (#393) リポジトリ設定のグローバルなオーバライドをサポートした。 #472 再コンパイルをせずに unchecked と deprecation の警告を表示する print-warnings タスクを追加した。(Scala 2.sbt プラグインのまとめ
XML ベースのビルドツールと比較すると sbt はビルド定義を (.sbt と .scala の両方とも) Scala を使って書くという違いがある。それにより一度 sbt のコンセプトや演算子を押さえてしまえば、ビルドユーザが sbt プラグインを書き始めるのにあまり労力がいらない。 既にあった sbt 0.7 のプラグインも移植してきたが、オリジナルのも書いているのでまとめて紹介したい。 sbt-dirty-money sbt-dirty-money は Ivy キャッシュを何となく選択的に消去するためのプラグインだ (~/.ivy2/cache 下の organization と name を含むもの)。たった 25行の簡単な実装だけど、clean-cache と clean-local の 2つのタスクは僕の役に立っている。 例えば、何かプラグインを開発していてそれがテスト用の hello プロジェクトにおいてキャッシュされているかどうかが不明であるとする。 プラグインプロジェクト中から clean-cache と clean-local の両方を走らせ、hello プロジェクトを reload することでプラグインが解決できないかどうかを確認する。解決できなければ、どこか知らない所から引っ張ってきてるわけではないということなので成功だ。 sbt-buildinfo sbt-buildinfo は前から書こうと思っていたプラグインの一つだ。これはビルド定義から Scala のソースを生成する。主な目的はプログラムが自身のバージョン番号を意識することにある (特に、conscript を使ったアプリの場合)。 sourceGenerators を使ってバージョン番号を含むオブジェクトを生成するスクリプトをちゃちゃっと書いたことが何回かあったが、他の人にも使ってもらえるようにするにはプラグインにするのが適してると思った。state から値を抽出することで sbt-buildinfo は任意の複数のキーから Scala ソースを生成する。以下を build.sbt に加える: buildInfoSettings sourceGenerators in Compile <+= buildInfo buildInfoKeys := Seq[Scoped](name, version, scalaVersion, sbtVersion) buildInfoPackage := "hello" これで以下が生成される:Scala 並列コレクションライブラリ
並列コレクションライブラリのガイドを翻訳して、docs.scala-lang.org に取り込んでもらいました。 原文は EPFLの研究アシスタントで、並列コレクションの設計書である A Generic Parallel Collection Framework (pdf) という論文の第一著者でもある Aleksandar Prokopec さんと 現在アメリカから EPFL に留学中で、並列と分散プログラミングモデルを研究していて、コミュニティ内ではドキュメンテーションツァーとしても知られる Heather Miller さんです。
treehugger.scala pamflet
treehugger はコードを用いて Scala のソースコードを書くためのライブラリだ。それはまた、Refelection API に基づく Scala AST の代替実装の一つでもあり、github で eed3si9n/treehugger として公開している。 更新: この記事を拡張して本当かっこいい n8han/pamflet を使ってガイドに仕上げてみました(今のところ英語だけです): treehugger のパンフレット暗黙のパラメータ解決優先順位
Scala という言語は、僕の使ったことのある中では最もエレガントで、表現力に富み、一貫性があり、かつ実利的な言語の一つだと思う。パターンマッチングや統一形式アクセスの原則などはじめ、その筋の良さは枚挙にいとまがない。そして、Scala エコシステムと Scala コミュニティーはその言語をより強力なものにしている。
Scala 2.9.1 において、ローカルで宣言された implicit はインポートされたものよりも優先される。問題は、言語仕様にはそのような振る舞いは書かれていないことだ。僕の当初の仮説は、自分が言語仕様を正しく理解していないか、もしくは言語仕様に抜け穴があるかのどちらかだろうというものだった。とにかく、その仮説に基づいて暗黙のパラメータ解決の優先順位について色々調べた結果を先週書いた。「怪しい伝説」でもよく言われるように、全く予期していなかった結果が出てきたときが最も面白いものとなる。後で分かったのは、仮説の両方とも間違っていたということだ。
つまり、関連部分に関する僕の仕様の理解は正しく、仕様も正しいということだ。SI-5354 によると、間違っていたのはコンパイラの実装だった。
再考「import 税のかからない implicit」
Northeast Scala Symposium 2012 もあと数ヶ月という所だけど、2011年をまとめるという形で去年のシンポジウムでの発表の一つを再考してみたい。とにかく、nescala は次から次へとクオリティの高い発表があった。これらの全ては、ここで見ることができる。Daniel の関数型のデータ構造と Janas の Akka がそれぞれ一時間のキーノートがあったこともあり、Scala コミュニティーの中に FP とアクターという二つの潮流が形成されつつあることが印象に残った(Paul がアクターのメッセージの送信には参照透過性が無いと宣言したのもヒントだったかもしれない)。また、一年のその後の予兆とも言えた Mark の sbt 0.9 のプレゼンや Nermin による Scala のパフォーマンスに関する考察もあった。しかし、僕の中で直ちにコードを変更する必要に迫られような直接的なインパクトという意味で抜きん出た発表は Josh の発表だった: Implicits without the import tax: How to make clean APIs with implicits. (import 税のかからない implicit: implict を用いていかにクリーンな API を作るか) ビデオ スライド 暗黙のパラメータ解決 Josh の発表の大きな点は、暗黙のパラメータ (implicit parmeter) はいくつものレイヤーを順番に見ていくことで解決され、ワイルドカード import は高い優先順位を占めるため、ライブラリがそれを使ってしまうとユーザがそれをオーバーライドできなくなってしまうということだった。 このポストにおいて、implicit の解決優先順位を Scala Language Specification を読んだりコードで試していくことで探検していきたい。せっかちな人のために、最終的に導きだされた優先順位を以下に示した: Implicits with type T defined in current scope. (relative weight: 3) Less specific but compatible view of type U defined in current scope.Iterator パターンの本質
これは Scala Advent Calendar 2011 の 17日目の記事です。 specs2 の作者であり、@etorreborre としても活発に発言を続けるシドニーの強豪 Eric Torreborre さんが書いた “The Essence of the Iterator Pattern” を翻訳しました。翻訳の公開は本人より許諾済みです。翻訳の間違い等があれば遠慮なくご指摘ください。 2011年6月24日 Eric Torreborre 著 2011年12月17日 e.e d3si9n 訳 去年読んだ論文で一番気に入ったのは “The Essence of the Iterator Pattern”(以下、EIP)だ。これを読んだ後で、今まで何年も使い続けてきたあるものに対する考えがガラリと変わった。それは、for ループだ。 この論文の中からいくつかのアイディアを紹介して、書かれている解法の実装方法を Scalaz っぽいコードを使って説明する。以前に関数型プログラミング、ファンクタ、モナドなどに少しでも触れたことがあれば、役立つと思う! for ループの中身は何だ? これが、本当に僕がハマったキッカケだ。「for ループの中身は何だ」とはどういう意味だ? 僕が何年も使ってきたこの構文に、何か魔法は入っていないだろうか? EIP の導入部に、(C のような添字を使った for ではなく)各要素を一つづつ順に返すタイプの for ループの例がでてくる。ここでは、Scala に変身させて書くけど、考え方は一緒だ: val basket: Basket[Fruit] = Basket(orange, apple) var count = 0 val juices = Basket[Juice]() for (fruit <- basket) { count = count + 1 juices.フィールドテスト: conscript, giter8, sbt-dirty-money
Scala のツールを使った、日常のコーディングでのテクニックを紹介したい。 例えば、ツールとかライブラリを開発してるとして、バグ報告を受けるとする。まず原因の分析に入る前に僕が集中することは、ユーザが使っているのと同じデータで問題を再現することだ。問題が再現できれば、次に問題を単純化して失敗する spec や機能テストに落としこむことに移行する。バグが修正されれた後で、同じセットアップを使って実際のデータでもバグが直っているかを確認することができる。
始める sbt: 公式ガイド
sbt プロジェクトからついに、公式ガイドと言える Getting Started Guide が出てきたので、翻訳しました。原文は、Heroku に Scala を載せたりなんかしてる、Typesafe 社の Havoc Pennington 氏により全て書かれています。
非公式 sbt 0.10 ガイド v2.0
version 2.0 2011年6月19日に最初のバージョンを書いた時点での僕の動機は、運良く Mark による sbt 0.10 のデモを二回も生で見れたことに触発されて(最初は northeast scala、次に scala days 2011)、sbt 0.7 から 0.10 へと皆が移行するのを手助けしたかったからだった。プラグインがそろっていなければビルドユーザが 0.10 に移行できないため、プラグインが移行への大きな妨げになるというのが大方の考えだった。そこで僕が取った戦略は、無いプラグインは自分で移植して、つまずいたらメーリングリストで質問して、結果をここでまとめるというものだった。それにより、多くのポジティブな反応があったし、数人を 0.10 へ移行する手助けにもなったと思う。だけど、後ほど明らかになったのは、僕の sbt 0.10 に関する理解は完全なものではなく、時として全く間違っており誤解を与えるものだったということだ。文責は僕にあるが、古い内容をそのまま残しておくのではなく、github に push して、新しいバージョンを作って、前へ進むことにした。プラグインの作成に関する最新の知識は Plugins Best Practices にまとめられており、大部分は Brian と Josh、ちょこっとだけ僕により書かれている。 慌てるな (don’t panic) さっき 0.7 の世界から着陸したばっかりの君。sbt 0.10 があまりにも違うのでビックリすることだと思う。ゆっくり時間をかけて概念を理解すれば、必ず分かるようになるし、sbt 0.10 の事がきっと大好きになることを約束する。 三つの表現 sbt 0.10 とやり取りするのに三つの方法があるため、最初は混乱するかもしれない。 sbt 0.10 を起動時に現れるシェル。 build.sbt や settings 列に入る Quick Configurations DSL。 普通の Scala コード、別名 Full Configuration。 それぞれの表現は別々の使用モデルに最適化している。sbt を単にプロジェクトをビルドするのに使っている場合は、ほとんどの時間を publish-local などのコマンドを使って、シェルの中で過ごすだろう。次にライブラリの依存性など基本的な設定の変更を行いたい場合、build.sbt の Quick Configurations DSL に移行する。最後に、サブプロジェクトを定義したり、プラグインを書く場合には、Full Configuration を使うことで Scala のパワーを発揮することができる。sbt プラグインをテストする
テストの話をしよう。一度プラグインを書いてしまうと、どうしても長期的なものになってしまう。新しい機能を加え続ける(もしくはバグを直し続ける)ためにはテストを書くのが合理的だ。だけど、ビルドツールのプラグインのテストなんてどうやって書けばいいんだろう?もちろん飛ぶんだよ。 scripted test framework sbt は、scripted test framework というものが付いてきて、ビルドの筋書きをスクリプトに書くことができる。これは、もともと 変更の自動検知や、部分コンパイルなどの複雑な状況下で sbt 自体をテストするために書かれたものだ: ここで、仮に B.scala を削除するが、A.scala には変更を加えないものとする。ここで、再コンパイルすると、A から参照される B が存在しないために、エラーが得られるはずだ。 [中略 (非常に複雑なことが書いてある)] scripted test framework は、sbt が以上に書かれたようなケースを的確に処理しているかを確認するために使われている。 正確には、このフレームワークは siasia として知られる Artyom Olshevskiy 氏により移植された scripted-plugin 経由で利用可能だが、これは正式なコードベースに取り込まれている。 ステップ 1: snapshot scripted-plugin はプラグインをローカルに publish するため、まずは version を -SNAPSHOT なものに設定しよう。 ステップ 2: scripted-plugin 次に、scripted-plugin をプラグインのビルドに加える。project/scripted.sbt: libraryDependencies <+= (sbtVersion) { sv => "org.scala-sbt" % "scripted-plugin" % sv } 以下を scripted.sbt に加える: ScriptedPlugin.scriptedSettings scriptedLaunchOpts := { scriptedLaunchOpts.value ++ Seq("-Xmx1024M", "-XX:MaxPermSize=256M", "-Dplugin.sff4s: simple future facade for Scala
future の実装には様々なものがあるけど、標準ライブラリの中に共通の親 trait があれば、特定のプラットフォームスタックにコードを依存させずにこの概念を表現できるのにと思っていた。そう思う人が他にもいるかは分からないけど、ライブラリの作者なんかには役に立つんじゃないかな。取り敢えずこれが、sff4s を書いた動機だ。 future って何? 多分名前ぐらいは聞いたことあるかもしれないけど、一応おさらいしよう。future値(promise とも呼ばれる)は未完の計算を表現する。 future値は未完の計算を表現する。 これがよく使われる説明だけど、それだけでは分からない。ここで言外に含まれているのは、その計算は裏で行われているということだ。それは同じコンピュータ内の別のスレッドか、別のサーバの中かもしれないし、行列待ちでまだ計算は始まってさえいないかもしれない。とにかく、計算は現在の制御フローの外で行われているということだ。 計算はどこか別の所で行われる。 future値のもう一つの側面は、そのうちに計算結果を得られるということだ。Scala の場合は def apply() を呼び出すなどの明示的なステップを要する。計算が未完の場合は、ブロック(block)する。つまり、計算結果が得られるまで待たされる(もしくはタイムアウトする)。 future値から計算結果を得ることができる。 最初に future値が宣言された時には計算結果は有るかもしれないし、まだ無いかもしれない。うまくいけば、ある時点で結果が到着し、オブジェクトの内部構造が変更される。これを、future値を「解決」(resolve)したという。勝手に状態が変わるものというのはプログラミングではあまり見かけないので、少し不気味ではある。 計算結果を解決するための裏口がある。 これまでで、最も単純な形の future値を記述した。実際に役に立つには他の機能も必要だけど、これでも使えないことはない。ちょっと使用例をみてみよう: val factory = sff4s.impl.ActorsFuture val f = factory future { Thread.sleep(1000) 1 } f() // => これは 1秒間ブロックした後で 1 を返す 細かい事は気にしないで、最後の一行の振る舞いだけ見てほしい。このように、計算結果を取得することを、強要(forcing)するともいう。最小限の API は以下のようになる。 Future v0.1 abstract class Future[+A] { /** 計算結果を強要して無期限にブロックする */ def apply(): A } Scala から使用可能な future値の実装にはいくつかあるけど、どれも一から書かれてる。上のような共通な親クラスがあれば、特定のライブラリに依存しないコードを書くことができる。 まだ来ない? Future v0.1 に対して唯一できる事が計算結果が戻ってくるまでブロックしてしまうので、あまりにも不便だ。待つことしかできないから future を使わないほうがいい。そのため、全ての future値が提供するもう一つの機能として、計算結果の用意ができたかを確かめるノンブロッキング(non-blocking)な方法がある。これは実装によって isDone、isSet、isDefined、isCompleted などと呼ばれているが、全て同じ意味だ。今のところ、僕の好みとしては def isDefined: Boolean がいいと思う。future を概念的に Option の変数として考えることができるからだ。モナドはメタファーではない
Scala界の関数型プログラミング一派を代表する論客の一人、@djspiewak が 2010年に書いた “Monads Are Not Metaphors” を翻訳しました。翻訳の公開は本人より許諾済みです。翻訳の間違い等があれば遠慮なくご指摘ください。
2010年12月27日 Daniel Spiewak 著 2011年5月29日 e.e d3si9n 訳
僕は今、約束を破るところだ。およそ三年前、僕は絶対にモナドの記事だけは書かないと自分に約束した。既にモナドに関する記事は有り余っている。記事の数が多すぎてその多さだけで多くの人は混乱している。しかも全員がモナドに対して異なる扱い方をしているため、モナドの概念を初めて学ぼうとする者は、ブリトー、宇宙服、象、砂漠のベドウィン (訳注: アラブ系遊牧民) の共通項を探す努力をするハメになっている。
僕は、この混乱した喩え話のサーカスにわざわざもう一つ追加するようなことはしない。まず、どの喩え話も完全には正確では無い。どの喩えも全体像を伝えきれていないし、いくつかは重要な点に関して露骨に誤解を招くような内容になっている。メキシコ料理や宇宙(そら)に思いをはせることでは、絶対にモナドを理解することはできない。モナドを理解する唯一の見方は、それをありのままの姿、つまり数学的概念として見ることだ。
実戦での Scala: Cake パターンを用いた Dependency Injection (DI)
Akka の作者として益々注目を集めている Jonas Bonér が 2008年に書いた “Real-World Scala: Dependency Injection (DI)” を翻訳しました。翻訳の公開は本人より許諾済みです。翻訳の間違い等があれば遠慮なくご指摘ください。 2008年10月6日 Jonas Bonér 著 2011年4月22日 eed3si9n 訳 さて、実戦での Scala シリーズ第二弾の今回は、Scala を用いた Depenency Injection (DI) の実装をみていきたい。Scala は、備わっている言語機構だけを用いても何通りかの DI を実現できる非常に豊かでディープな言語だが、必要に応じて既存の Java DI フレームワークを使うこともできる。 Triental では、一つの戦略に落ち着くまで三つの異なる方法を試した。以下のように話を進めていく。まず、現行の DI の実現方法を詳しく説明した後で、試した他の方法も簡単にカバーする。 Cake パターンを用いる 私たちが用いている現行の戦略は、いわゆる Cake パターンに基づいている。このパターンは、Martin Odersky の論文 Scalable Component Abstractions において、Ordersky と彼のチームが Scala のコンパイラを構成した方法として最初に発表された。このパターンがどのようにして DI を実現するのかということを日本語で説明する事を試みるよりも、(私たちの実際に使っているコードに大まかに基づいた)愚直なサンプルコードをみてみよう。 注意: 順を追って、最終バージョンに向けてリファクタリングしながら説明していくので、最終バージョンを読んで理解するまでは、「ダメじゃん!」と叫ぶのは待ってほしい(もちろん、読了後にどうしてもと言うなら批判、賞賛、意見、アイディアなどを送ってもいい)。また、このサンプルコードは、このようなサンプルの例にもれず、非常に複雑な方法で取るに足りない事を行っているようにみえるが、我慢して大規模システムでの実際のサービスを想像して、どのように応用できるかを想像して欲しい。 まずは、UserRepository (DAO、Data Access Object) を実装しよう。 // 実際の永続化は何もしていなくて、画面にユーザを表示するだけのダミー。 class UserRepository { def authenticate(user: User): User = { println("authenticating user: " + user) user } def create(user: User) = println("creating user: " + user) def delete(user: User) = println("deleting user: " + user) } trait インターフェイスとその実装に分けて実装することもできたが、話を簡単にするために、敢えてここではそうしなかった。Scala と Json で tweed を織る
次々とヤバいコードを紡ぎ出し NY Scala シーンの中心的存在であり続ける @n8han が二年前に書いた “Weaving tweed with Scala and Json” を翻訳しました。翻訳の公開は本人より許諾済みです。翻訳の間違い等があれば遠慮なくご指摘ください。 2009年5月27日 n8han 著 2011年1月2日 eed3si9n 訳 抽出子は、Programming in Scala の 24章にのみ記述されている Scala の秘密機能で、この春の大ヒットだ。今までは皆 case Some(thing) => kerpow(thing) で満足だったのが、今では抽出子を書けなければ #scala freenode にも入れてもらえない。ズルをすれば Scala チャンネルの硬派な常連たちは君のコンピュータをハックして驚くほど馬鹿げたドールハウスを連続再生して(ただし混浴シャワーシーンを除く)、番組の「アクティブ」のように意味のあるタイピングを諦めなければいけない。 訳注。以下 Draco より抜粋 ロッサム・コーポレーションは人間の人格、経験をすべて消し、新しい人格を植え付ける技術を開発した。彼らはこの技術を用いて、戦闘用の人形アクティブを生み出した。 人形たちはドールハウスという施設で生活している。誰かの人格を移植され、任務に挑む。 アクティブの一人、エコーは記憶のリライト中にエラーが起こり、完全には記憶が消されていなかった。 この抽出子はちょっとチクっとしますからね 命からがら逃げ出した僕は抽出子をありとあらゆる状況に適用するよう努めた。例えば、JavaScript インタプリタが理解できるお洒落な文字列、Json オブジェクトだ。抽出子を使えば case 構文でこのように処理することができる: import dispatch.json.Js val echo = Js("""{"acting": "無表情で前を見ている"}""") object Echo extends Js { val acting = 'acting ? str } echo match { case Echo.IntelliJ IDEA のための Twilight
Scala をやりながら他の IDE も試しましたが、結局 TextMate に戻っています。 今回巷で話題の IntelliJ IDEA に便乗するにあたって、Twilight theme を作りました。