kmizuの日記

プログラミングや形式言語に関係のあることを書いたり書かなかったり。

シンフォニック=レインというゲームをお勧めしてみる(注意:ネタバレは見ないで)

このブログでオタク系の話題を書くのは、もしかしたら初めてかもしれませんが、表題のゲームのSteam版が発売されるというニュースを見つけたので、このゲームが好きな人間としてこれを機会に布教しとこうかと思って筆をとりました。

シンフォニック=レインは、2004年3月に工画堂スタジオから発売された、全年齢向けゲームです。ジャンルはPCからはほとんど姿を消した、いわゆるギャルゲ(健全)です。普通の紙芝居形式のギャルゲと違う特徴としては、ミュージックアクションパート、という、音符に対応したキーボード上のキーを適切なタイミングでタイプするゲームが要所要所にあることですが、音ゲー苦手な人用に完全スキップも可能になっています。

作曲・作詞を担当した岡崎律子氏がこの作品が出た2か月後くらい後にお亡くなりになってしまったため(胃ガンだったそうです。ゲーム中の曲も闘病中に作られたものです)、ゲームには興味ないけど岡崎氏のファンが注目するとかいうこともありました。

このゲーム、爆発的な人気こそ出なかったものの、コアなファンがずっといる不思議なゲームで、これまで、

  • 初回限定版/通常版
  • 愛蔵版
  • 普及版
  • Steam版(2017/06発売)

と版を重ねてきています。なんで根強いファンがいるかというと、一つにはシナリオの出来の良さ、二つ目は楽曲自体が物語と密接にリンクしているという巧さがあるのかなと思います。

あらすじを簡単に紹介しておくと、主人公のクリスはフォルテールという架空の楽器を演奏する才能が生まれつきありました(劇中では、魔力とされていますが、魔力とは何かが劇中で明かされることはないので、単に楽器演奏の才能があったと言い換えていいです)。クリスには幼馴染の双子姉妹アリエッタとトルティニタがいるのですが(ありがち設定ですね)、姉のアリエッタには歌とか音楽の才能がなく、妹のトルティニタには反対に歌の才能がありました。

結果として、思春期になって、クリスはアリエッタと恋人になるのですが、音楽家への道を志すために、音楽の街と呼ばれるピオーヴァの音楽学院にアリエッタの妹トルティニタと共に通うことになります。主人公たちの家とピオーヴァは電車で1日以上離れているので、普段のやり取りは手紙のみです(電車はあるのですが、電話はない世界観です)。

で、それから3年近くが経って、卒業まで残り2か月程度。卒業演奏のための曲を作る必要と、歌を歌うパートナー(同性でもいい)を早く見つけなければいけないのですが、クリスはやる気ナッシング。ピオーヴァの下宿に引っ越してから何故か見えるようになった妖精フォーニ(他の人には見えないので幻覚の恐れあり)とじゃれあいながら自堕落な生活を過ごしています。

そんなクリスに対して、トルティニタはさっさと自分あるいは他の誰かとパートナーを組ませようと色々根回しをしたりするのですが、それもなかなかうまく行かず、さて、どうなるんでしょうね?というところで物語がスタートです。

嘘は書いていませんが、微妙に興味を引くようにあらすじの状況を言い換えてみました。この辺で何かピンと来るものがあった人がいれば、6月に発売のSteam版をぜひ買いましょう。

既にロットアップして久しいですが、中古でもまだそこそこ売っているはずなので、今すぐやりたい人は中古買いましょう。普及版が、だいたい、追加要素全部込みなのでお勧めです。

以下、ネタバレ注意のため反転(ただし致命的なことは書いてないので、読んだ上で状況を考えながら楽しむのもありですし、興味わかなかった人が読んでみて興味がわくこともあるかもしれないので、興味ない人はむしろ積極的にみるの推奨です)。

このゲームには、自分が思うところでは、中盤までに3つの「謎」あるいは「不審な点」があることに多くのプレイヤーが気づくと思います。そのうちの1つはたぶん割とわかりやすいので、確信を持てるのは後半になるにしても、序盤でん?と思うだろうと思います。

残りのうち1つは、ある程度物語が進んできて、最初の一つの点について疑問に思ったあたりで、必然的に、こっちの点についても気づくと思います。ただ、この点についてのみ若干ファンタジー要素があり、それを徹底的に排除した作品としてとらえると気づくのがだいぶあとになるかなとも思います。

最後の1つは常識的に考えて、まず無理というタイプですが(それで、最後の一つがどういうタイプの「謎」なのかわかった人もいると思います)、物語中に気づくためのヒントは一応提示されており、謎が明かされてからみると、登場人物たちの一見よくわからない不審な行動にちゃんと一貫した筋が通ってるのが2度読んでわかるあたり、割と良い作品である証だと思います。裏がわかったら冷めるとかいうタイプではなく、裏がわかったあとで、最初から読み直してみると全く違った風に読めます。

というわけで、普段技術ネタばかりのこのブログですが、珍しく趣味的なゲーム紹介をしてみました。全体的にダウナーな雰囲気のゲームで、決して読んでいて楽しい作品ではないですが、それでも面白いのは確かなので、是非、買ってみてください!

Scalaでimplicits呼ぶなキャンペーン

  • はじめのはじめに

    • implicitsは可読性が…という人が居たら、この記事へのリンクを教えてあげていただければと思います
  • TL;DR

    • Scalaには俗に「implicits」と呼ばれる機能がある
    • 実際にはそれらは3つの機能をまとめて指す用語である
    • それぞれの機能は全く異なる
    • 暗黙の型変換は現代では無視してよし
    • 拡張メソッドは、既存の言語でそれを持つのと同じ程度の簡単さである
    • 型クラスとしての用法は、型クラスがある言語を知らないとやや難しいが、積極的に使う価値がある機能である
    • 「implicits」は異なる3つの機能を一つにまとめた呼び方に過ぎず混乱を招くので、使うのをやめよう(個々の機能名で呼ぼう)。また、暗黙の型変換は無視して良いし、拡張メソッドはよく知られているので、型クラスとしての用法にフォーカスして良い
  • はじめに

Scalaには俗にimplicitsと呼ばれる機能(群)があります。(群)と書いたのは、implicitsというのは実は単機能ではなく複 数の機能を指すからなのですが、このことがScalaに関する理解を妨げ、また、Scalaのimplicitsを難しい、黒魔術である、という印象に貢献していると確信しています。

そこで、implicitsに見られる3つの機能群に対して、適切な名前をあたえることでむやみに恐れる必要がないことを示したいと思います。

  • 暗黙の型変換(implicit conversion)

皆さんがimplicitsと聞いたときに最も多く思い浮かべるであろう機能です。が、忘れてください。2017年どころか数年前から、もうこの機能は好ましいものとみなされなくなっており、最近では、Javaのコレクションとのimplicit conversionを提供する標準ライブラリJavaConversionsは非推奨になっています。本当に例外的な目的に限ってのみ使用しても良い機能です。再度いいますが忘れてください。覚える必要がありません。

  • 拡張メソッド(enrich my library)

()内はScalaで従来どう呼ばれていたか、という呼称ですが、一般的な呼称として拡張メソッドとして読んで問題ないでしょう。たとえば、整数nにn回繰り返すtimesメソッドを追加するのは

implicit class RichInt(self: Int) {
  def times(block: => Unit): Unit = {
    var n = 0
    while(n < self) {
      block
      n += 1
    }
  }
}

と書くことで実現できます。このメソッドは、Intをレシーバとする(self: Int)ので、

3.times {
  print("A")
} // => AAAを表示

のように呼び出すことができます。

実は、Scala 2.9以前はより冗長な記法を使う必要がありましたが、Scala 2.10(4年以上前にリリースされたバージョン)からはこの書き方で、Int型にtimesメソッドを生やすことができるようになりました。新しくScalaを始める人はこの書き方だけ覚えていれば(だいたい)大丈夫です。いちいちRichIntと名前を付けるのが煩わしいと感じるかもしれませんが、大した問題ではありません。余分な情報はRichIntの名前の部分のみですから。

拡張メソッドを持つ言語には、C#、Kotlin、Swift(条件によるインポートができないのでちょっと違いますが)があります。これらの言語で拡張メソッドの有害性をうたう人はあまり居ないので、この機能を問題にする必要はないでしょう(自分は同程度に「問題」だとは思うのですが、一般的にはそういう認識だろうと感じています)

  • 型クラス(type class pattern)

最後の一つである型クラスとしての使い方は、とても有用である一方で、若干難しいと感じられるものかと思います。 ここでは、その威力を示すにとどめて、詳細な解説は別のページを探してもらうことにしようと思います。Scalaのコレクションにsumメソッドというのがあります。

これは、コレクションの要素を全て「足し合わせて」その合計値を返す、というメソッドです。

たとえば、

List(1, 2, 3, 4, 5).sum // => 15

でも

List(1.5, 2.5, 3.5).sum // => 7.5

でも同様にメソッドが動作するという点です。sumメソッドが1バージョンしか定義されていないにも関わらず、です。また、自分で有理数型を定義した場合にも、(定義を一切変えずに)このsumメソッドを利用することができます。この機能が非常に強力であることが理解できたと思います。

型クラスとしての使い方は有用性が非常に高く、積極的に使う価値がある機能です。もちろん、きちんとしたドキュメンテーションは必要ですが、あまり恐れる必要はありません。

  • まとめ

implicitsと俗に言われる3つの機能について別個に解説しました。もう「implicits怖い」と言うのは止めましょう。そのような機能は「存在して」おらず、3つの機能が便宜上そう呼ばれているだけなのですから。さらに、暗黙の型変換は無視すべきですし、拡張メソッドは従来いくつもの言語に存在するのですから怖がるほどのものではありません。型クラスとしての使い方のみにフォーカスして理解すればそれで事足ります。これで、もう「implicits怖い」と言う必要はなくなりましたね?

Rubyっぽく楽にIO処理を書けるライブラリScaruby 0.3をリリースしました

Scalaは標準IOライブラリが非常に貧弱な言語です。scala.ioはまともに使えるものではありませんし、JDKのライブラリのIOを使うのも面倒です。そこで、サードパーティのIOライブラリを使うことになります。そこで、いくつかサードパーティのIOライブラリを見てみたところ、いずれも自分のやりたいことをぱっとできるように思えなかったので、自分で作ってみることにしました。

なお、better-filesは、自分の要求に一番近かったですが、java.ioやjava.nioがインタフェース部に露出しているのがあまり好みではありませんでした。

そこで、

  • java.ioがインタフェースに露出しない
  • Rubyのように簡単なIO処理が簡単に書ける
  • リソースの後始末は可能な限り簡単に
  • 多数のリソースをネストせずに扱える
  • オーバーロードをしない(!)

を目標として、新しいライブラリScarubyの開発を始めました(Scala + Rubyというネーミングです)。これまでで、とりあえず簡単なファイルI/OやURLからのテキスト読み込みなどが動作するようになったので、公開することにしました。

サンプルプログラムのいくつかは以下のサイトに置いてありますが、ドキュメントの充実はまだまだこれからということです。

github.com

たとえば、次のようなプログラムが動作します。

import com.github.scaruby._

val content = SFile.read("file.txt")
import com.github.scaruby._

val input = "Hello, World!"
val encoded = SBase64.encode64(input.getBytes("UTF-8"))
val decoded = new String(SBase64.decode64(encoded), "UTF-8")
assert(input == decoded)
import com.github.scaruby._
val content = for { 
  r <- SURL("https://srad.jp/").openReader
} r.readAll()
println(content)
import com.github.scaruby._
println(SURL("https://srad.jp").read())
import com.github.scaruby._
SFile("file.txt").read()
import com.github.scaruby._
SFile("output.txt").write("HogeFuga")

今後の予定としては、

  • JSONエンコーダ/デコーダの追加(他に依存しないもの)
  • その他のファイルフォーマットの対応

などを考えています。要望があればIssueに上げていただければ励みになります。

Scalaに関する誤解と事実を語る

TL;DR

  • 世間のScalaに関するイメージは、昔のままであることが多い
  • 昔のままどころか、最初から間違ったイメージを持たれていることも多い
  • 実際には、既に解決されている問題は多々あるし、改善に向かっていることも多い
  • プロジェクト管理の問題を言語に押し付けているケースもある

はじめに

自分が最初にScalaに触れたのが2005年(Scala 1からカウントした場合)、あるいは2007年(Scala 2以降からカウントした場合)と、Scalaとの付き合いも結構長くなってきましたが、その間に

  • Typesafe社(現Lightbend社)の設立
  • 実質標準ビルドツールとしてのsbtの確立
  • ライブラリのバイナリ後方互換性に関するポリシーの策定
  • 公式ScalaイベントScala Daysのはじまり
  • Play 2 Frameworkの登場
  • Scala Center発足
  • その他色々

がありました。この間、Scalaコミュニティ自身も変化してきており、昔のScalaに対する印象が今のScalaに対しても正しいとは言えなくなっています。そこで、Scalaに関する「誤解」(とは言い切れないのですが、現在はあてはまらないもの)と「事実」についていくつか語っておこうと思います。

誤解1:Scalaコンパイルが遅い

Scalaの欠点の筆頭に挙げられるコンパイル速度の問題ですが、誤解ではありません。たとえば、Javaコンパイル速度と比べると遥かに遅いですし、Scalaプログラマはこのことをよくネタにするくらいです。

ただし、たとえば、Kotlinがコンパイル速度がScalaより速いといった風聞は必ずしも事実に基づかないものです(KotlinとScalaコンパイル速度比較についてはこちら)。

また、これは多くの人が犯している過ちだと思うのですが、Scalaの標準ツールであるsbtは立ち上げたまま様々なコマンドを発行して利用することが前提のシェルでもあり、起動したままコンパイルを続けるとコンパイラの速度は倍以上高速になります。このことを知らないまま、毎回sbtを立ち上げなおしていると、せっかくJVMのwarmupによって高速になったコンパイル速度を無駄にしてしまうことにつながります。

なお、Scala 3のコンパイラになることが決まっているDotty

github.com

は現在のscalacに比べて2倍程度高速らしいです(これについては実測していません)

また、scalacのコンパイルを並列化するというアプローチで、Triplequote社がHydraという並列Scalaコンパイラを提供しています。Hydraは現在はOSSでなく、限られた顧客にのみ提供されているようですが、コンパイラをうまく並列化することによって、10コアのサーバマシンにおいて、大規模プロジェクトのビルドがおよそ6.3倍高速したとのことです。これが典型的なデータであれば、今後コア数がさらに増えることが予想されるなかで、ScalaのビルドもPCの多コア化にともなって高速化することが期待できそうです。

もし、HydraがOSS化されることがあれば、Scalaの(コンパイル)遅い、は過去の話になるかもしれませんね。

誤解2:Scalaは(実行速度が)遅い

これは紛れもない誤解、というか、間違い、なので、はっきりとそのようなことはないと言っておきましょう。

scalacのコンパイルしたコードを逆アセンブルしてみた人ならわかると思いますが、scalacの吐くコードというのは極力JVMの命令を直接呼び出すようになっています。たとえば、基本型がオブジェクトであるといったことから、基本型を使うのにもオブジェクト生成が伴うイメージを持っている方もいるようですが、基本型がオブジェクトであるというのは単にそう取り扱って問題ないように言語が設計されているというだけで、基本的にはJVMの基本型演算命令をそのまま使います。

ですから、Javaで速度的に問題ないケースであれば、Scalaを適用して速度的に問題はありません。

誤解3:Scalaでは記号メソッド(あるいは演算子オーバーロード)が濫用されている

これは、昔、Scalaを紹介するのに、foldLeftの別名である/:メソッドが使われたことの影響もあると思います。また、昔のScalaによるHTTPクライアントライブラリdispatch(-classic)において、記号が非常に多用されたことも影響しているでしょう。

現在の、というか、数年前からScalaコミュニティでは、記号メソッドの濫用については抑制的になっており(のはず)、むやみに記号メソッドを使うことには慎重になっています。たとえば 新しい方のdispatchでは記号メソッドは大幅に減っています。

誤解4:implicitは濫用されがちな機能であり、コードの可読性を下げるので良くない

これも昔のScalaコミュニティにおいてそういう傾向があった、という事実がベースにあるのだと思われます。しかし、現在は、既存の型と新しい型の間の変換を行う用途のimplicit conversionは既にアンチパターンとみなされています。たとえば、Scala 2.8から標準ライブラリにはJavaConversionsという、JavaのコレクションとScalaのコレクションを相互に暗黙的に変換するライブラリがありましたが、Scala 2.12ではこれは非推奨になり、その代わりに、asScala()asJava()などとして明示的に相互変換するための`JavaConvertersを使うべきということになっています。

いわゆるimplicitと呼ばれる機能群の中で現在も必要とされているのは、

  • 型クラス(implicit parameter)
  • 拡張メソッド(implicit class)

の主に二つですが、拡張メソッドは最近の言語ではよく見られるものですし、型クラスもその有用性については(Haskellなどの言語において)十分に実証されています。型クラスについても濫用は可能であるという批判はできますが、それをするにはまず型クラスを理解する必要があるでしょう。

誤解5:ScalazやCatsは、圏論とかなんか難しい知識が必要らしくて怖い

おそらく、ScalazやCatsの位置づけについて誤解があると思われるのですが、これらは別に準標準ライブラリという程ではなく、あくまでもサードパーティのライブラリに過ぎません。使いたくなければ使わなければいいだけの話です。既に導入されたプロジェクトについていくためには、ScalazやCatsを勉強する必要があるでしょうが、それは何のライブラリであっても同じことです。

なお、ScalazとかCatzのライブラリ名に圏論の影響があるのは間違いありませんが、実際に使うときにそれらの知識が必要かというと必ずしも必要ないと思います。

誤解6:Scalaは、手続型プログラミングも可能だと宣伝しているが、実質的には関数型プログラミングのスタイルで書かなければいけない!騙された!

これは誤解かどうかちょっと微妙なところです。というのは、実際には、Scalaで手続型プログラミングをするためのライブラリも多くあるのですが、関数型、とりわけ純粋関数型アプローチに基づいたライブラリが目立つという傾向はあり、そのため、このような感想が出てくるのかなと思います。あまり関数型関数型したものを避けたい場合、The Scala Library IndexというScalaライブラリ専用の検索エンジンで探してみると良いでしょう。

ただ、いくら、Scalaで手続型プログラミングが可能であるといっても、map一発で済む処理をいちいち可変コレクションをループで回していると、さすがにつらい、というか、Scalaで書くメリットがあまりないので、最低限、Scalaのコレクションライブラリは使えるべきだと思います(これは、Scalaに限らず、最近の言語はだいたい汎用コレクションに対する高階メソッドが標準であるので…)。

不変コレクションを多用することで、そのメリットを享受しつつも、DBとのやりとりなどの外界とのインタラクションについては無理やり関数型的に扱わずに、素直に手続型で扱うのが良いというのが現在の自分の意見です。

誤解7:Scala後方互換性を重視しない(あるいは無視する)

これに関しては、まず、ソース互換性(.scala後方互換性)とバイナリ互換性(.classの後方互換性)があることを認識する 必要があります。

その上でいうと、Scalaはソース後方互換性をなるべく維持するように進化してきました。Scala 2.10で コンパイルできるコードは(非推奨なライブラリを使っていなければ)、Scala 2.12でもほとんどのケースでコンパイルを通ります。というわけで、ソース互換性をScala開発チーム含むコミュニティはとても重視しています。

バイナリ互換性の問題について論じましょう。その前に、Scalaのバージョンに関して、

  • メジャー・バージョン: Scala 2.X.YのX(だいたい1年以上の周期でアップデート)
  • マイナー・バージョン: Scala 2.X.YのY(短いと1週間くらい、通常は数週間くらいのペースでアップデート)

です。この定義の上で、まず、同じメジャー・バージョンのScalaに対してコンパイルされたライブラリは、マイナー・バージョンが変わってもメジャー・バージョンが同じScala上では動きます。また、同じメジャーバージョンのScalaに対してコンパイルされたライブラリ同士を混ぜることも可能です。

ここで、「じゃあ、Scalaのメジャー・バージョンが上がった場合、そのためにライブラリを書き直さなければ、新しいScalaで使えないのか?」と思った方はいると思います。

その問題は皆無とは言えないのですが、よく使われているScalaライブラリは、sbtのクロスビルドという機能を使って、最低2世代、多いと3世代のメジャーバージョンに対してライブラリをビルドして対応しています。そのため、新しいScalaのメジャーバージョンが出たときの初期の頃こそ、対応ライブラリが出揃わないという問題はありますが(scala-library <- A <- B <- Cみたいな依存関係があると、Cは、AとBが対応してくれないと新しいScalaのメジャーバージョンに対応したものを出せないといったちょっと面倒な話はあります)、1ヶ月くらいすればだいたい落ち着くので、それほど深刻な問題であるとは思わないです。このとき、ライブラリのメンテナの作業としては、sbtの定義ファイル中の

crossScalaVersions

に、新しいメジャーバージョンを加えてライブラリをpublishするだけで良いので、それほど負荷が高い作業でもありません。Scalaの新しいメジャーバージョンが出た際、飽きたメンテナが自分のライブラリを更新しなくなることはよくありますが、多くの人に使われているものであればだれかがメンテを引き取ることもありますし、そうでなければそのライブラリの役割が終わった、ということだろうと思います。

このように、可能な限りソース後方互換性を保つことを前提とした上で、Scalaのメジャー・バージョン毎のバイナリクロスビルドによって、バイナリ後方互換性の問題に関してはかなり軽減することができていると言えます。もちろん、問題は皆無とは言いませんが、このことが致命的になったケースというのも思い浮かばないのが正直なところです。

なお、完全にバイナリ後方互換を保証するという選択肢もあったと思いますが、それではダメなライブラリはいつまでもダメなまま残ってしまいますし、JVMの新しい機能を利用できないというデメリットもあります。たとえば、Scala 2.12では、Java 8のinterfaceのデフォルトメソッドとラムダ式(というかinvokedynamic)を使うことで、クラスファイル数の削減と、ライブラリレベルでのバイナリ後方互換性を保ちやすくすることができるようになりました(Scala本体のバイナリ互換性を捨てることで、ライブラリのバイナリ互換性がかえって保ちやすくなるというのは面白いところです)。

一方、Kotlinでは、完全なバイナリ後方互換性を今のところ約束しているようですが(当面、Java 6で動作するバイナリを吐くことを明言しています)、これでは新しいJVMの機能は利用できないわけで、それでいいのかなあと思うところです。

たとえば、Kotlinでは、最新の1.1でも、Java 6相当のクラスファイルを出力しなければいけないせいで、実装ありのインタフェースが、実装ファイルとインタフェースファイルにコンパイルされます。これは、ライブラリを更新する際に、インタフェースにメソッドを追加するとバイナリ互換性が壊れてしまうことを意味します。バイナリ互換性を重視しているはずのKotlinで書いたはずのライブラリはバイナリ互換性を維持するのがより難しく、バイナリ互換性をKotlinほど重視していないはずのScalaで書いた(2.12以降)コードは、バイナリ互換性を保つのがより容易になるという皮肉な現象が起きるのです。

誤解ではない:Scalaは様々な書き方を許容するので、読みにくいコードが出来上がることがある

「誤解ではない」と書いた通り、そういう側面はあると思います。ただし、実際のプロジェクトではある程度のコーディング規約を定めるべきであることを考えると、コーディング規約を最初に一つ作る手間が削減できるくらいの意味しかないと思います。

また、今時のプロジェクトにおいて、メンバーがコミットしたコードに対してレビューがされるべき(建前じゃなくて普通にやりますよね?)ということを考えると、突然メンバーが変な書き方のコードを持ち込もうとしたら、それはコードレビューの段階でストップをかけるべき話なのではと思います。

これは、一昨年、とある会社がプロダクトコードをScalaからGolangに置き換えたという記事を見たときにも思ったことなのですが、たとえば <|*|>の意味がわからんという話なら、なぜそのコードをコードレビューではじかないのか、と(メソッド名からScalazのコード呼び出しであることは間違いないのですが、そんなコーディングスタイル全体に影響するライブラリを導入するのにちゃんと合意が取れてないというのはその会社の体制がgdgdなのでは、とか)。

おわりに

さて、だらだらと長い記事をお読みくださりありがとうございました。

自分がこれまでScalaについて観察を続けていて思ったことは、Scalaには今も昔も問題がたくさんありますが、問題が広く認識されれば、コミュニティもちゃんと解決に向かう健全さはある、ということです。最近の自分はあまりScalaコミュニティに対してコミットできていない気がしますが、今年はもうちょっとコミットしたいところです。ではでは。

Dottyで自作言語Klassicの処理系をビルドしてみる

つい先日、Scala 3になることが決定した次世代ScalaコンパイラDotty。このDotty、まだときどきコンパイラがクラッシュするなどのバグはありますが、Scala 2.11のライブラリを使うことができるので、Scala 2.11対応のライブラリやプロダクトを試しにビルドしてみることができます。

Dotty

に書いてある手順だけでは、Scala 2.11対応のライブラリを依存関係に含めることができないようです。Dottyで既存のソースをビルドするためには、次の手順に従う必要があります。まず、sbt-dottyプラグインをproject/plugins.sbtに含めます:

addSbtPlugin("ch.epfl.lamp" % "sbt-dotty" % "0.1.0-RC4")

バージョンが0.1.0-RC4という微妙な番号なので、適宜読み替えてください。次に、build.sbtのscalaVersionとlibraryDependenciesを次のように修正します。

scalaVersion := dottyLatestNightlyBuild.get

これでdottyのnightly buildを取得してこられるようです。また、libraryDependenciesには、次のように、依存関係の記述のあとに.withDottyCompat()の呼び出しを入れます。

libraryDependencies ++= Seq(
  ("org.scala-lang.modules" %% "scala-parser-combinators" % "1.0.4").withDottyCompat(),
  ("org.scalatest" %% "scalatest" %  "3.0.0").withDottyCompat()
)

また、project/build.propertiesではsbt.versionとして0.13.15を使うように指定します。

sbt.version=0.13.15

たったこれだけです。注意点として、現時点で(将来も?)structural typeはDottyで未サポートであるため、

def using[A <: { def close(): Unit}, B](resource: A)(f: A => B): B = try {
  f(resource)
} finally {
  scala.util.control.Exception.allCatch(resource.close())
}

のような形でLoan Patternを使っているライブラリは使わない形に書き換える必要があります。最後は、sbt run で実行してみます。

> sbt
> run -e "1 + 2 * 3 / 4"
[info] Running com.github.klassic.Main -e 1 + 2 * 3 / 4
2
[success] Total time: 1 s, completed 2017/05/04 9:28:25

問題なく実行できているようです。ただ、少し問題があって、sbt consoleを実行しようとすると、原因は不明なのですがNullPointerExceptionが発生するようです。ガッしたい気分ですね。

ジョギングを再開

かなりどうでもいい話なのですが、一応の区切りとしてここに記す。ちょっと最近身体の衰えを感じることが増えてきたので、今日からジョギングを再開する ことにした。とりあえず、だいたい2日おきに3kmくらいのジョグを1ヶ月続けて、その次は4kmを1ヶ月、5kmを1ヶ月…くらいのペースで 徐々に走行距離を長くできたら、と思っている。とはいえ、現状、3kmでも割と足がきついので、最初の2ヶ月を3kmくらいでちょうどいいかもしれない。

目標は、2017年11月に開催される(と思われる)つくばマラソン(フルマラソン)に出場して完走すること。

www.tsukuba-marathon.com

実は、学類3年(他大学の学部相当)のときに一度つくばマラソンをフルで走りきったことがあったのだが、そのときは、その後1ヶ月くらい筋肉痛で歩くのもしんどいみたいな状態であった。今年は、きちんと余力を残して完走することを目標にしたい。

それと並行して、体重というか体脂肪も落としていきたいところ。

というわけで、ツイッターとかでジョギングのツイートを見かけたらたまにでも応援してもらえると嬉しいです(?)

TwitterはScalaを捨ててません(少なくとも現在は)

なんだかTwitterの一部で

www.utali.io

の記事が話題になってるようですが、はっきり言って誤情報です(というか、何故そんな誤解をしたのか知りたいくらい)。根拠はいくつかありますが

  1. Twitterは最近(ここ数ヶ月)にScala CenterのAdvisory Boardにjoinしている
  2. 置換えたとされるFinagleのコミットが最近でも活発である
  3. そもそも引用元ツイートで一言も、Scalaを捨てたに相当する表現が見られない

1についてですが、Scala作者のMartin Odersky先生が

と書いています(引用元はこちら)。これが約1ヶ月前のことなので、1ヶ月前にTwitter社はScala Centerにjoinしたことになります。それなのにScalaを捨てるというのはちょっと考えづらい。

2について。当該記事において、Finagleを置換えたということが書かれていますが、Finagleのコミットは現在も活発に行われています(現在でもかなりの頻度でコミットが行われている)。

github.com

github.com

一応、確認しましたが、直近5コミットは少なくとも全てTwitter社のエンジニアによるものでした。反証としてはまあこれで十分でしょうか。

3について。いくつかのTwitter社エンジニアのツイートを引用されていますが、どこにもScalaを捨てたということに相当する表現は見られません。

最後に、そもそも論として、Finagleによってマイクロサービス化が進んでいるはずのTwitterが全部をごそっとNode.jsに置き換えるということは考えづらいです(必要なサービスだけ置き換えれば良い)。というわけで、TwitterScalaを捨てていない、のです(まあ、捨てていないという証明は無理ですが、少なくとも捨てたとする根拠が存在しない&現在も使っているという根拠が存在している)。