Ponylangで型付きActor生活

この記事は [第2のドワンゴ Advent Calendar 2015](http://qiita.com/advent-calendar/2015/dwango2)の15日目です。
14日目は[@toRisouP](https://twitter.com/toRisouP)さんの[音声認識で「結月ゆかり実況」動画を作る](http://qiita.com/toRisouP/items/979326f0ea5e944e1d3b)でした。

2015年新卒入社の[@matsu_chara](https://twitter.com/matsu_chara)です。
今日はPonylang(Pony)という言語の紹介をしたいと思います。

# Ponyとは

ざっくり言うと、Ponyは「Actorを使った並行処理を行うことが出来る静的型付けなオブジェクト指向言語」です。
[Causality](http://www.causality.io/)というロンドンの会社が中心になって作成していて、Ponyに関する技術サポートも行っているようです。
まだversion 0.2.1なので割と新しい言語です。[^pika]

[^pika]: v0.1.0のリリース日は2015/4/28です。 https://github.com/CausalityLtd/ponyc/releases

## 他の言語との違い

ActorといえばErlang・Elixir・Scala（Akka）あたりが有名だと思います。
ErlangやElixirは動的型付けな言語なので、静的型付けなPonyとはある程度異なる性質を持っていることが予想できます。一方でScalaは静的型付けなのでそういった意味で少し似ているかもしれません。[^akka]

[^akka]: ScalaのAkkaはreceiveが `Any => Unit` だから・・・みたいな話もありますが、最近ではdeprecatedになった[Typed Actors](http://doc.akka.io/docs/akka/snapshot/scala/typed-actors.html)に代わり、[Akka Typed](http://doc.akka.io/docs/akka/snapshot/scala/typed.html)というDSLベースでActorの振る舞いに型をつける取り組みが（まだexperimentalですが）進んでいるのと話の都合があるので、静的型付けということで・・。

関数型プログラミングのサポートを充実させているかオブジェクト指向に徹しているかという違いもあるのですが、Scala（やErlang, Elixirなどの言語)とPonyの大きな違いとして、単なる `type safety` だけではなく、並行処理で発生しがちな様々な問題をコンパイル時に検出するための `capabilities-secure` という概念を言語の中心に据えている点が挙げられます。

## Ponyの特徴

ここで公式で言われているPonyの特徴をいくつか見てみましょう。

* 型安全
    * Ponyで使われている型システムについての[論文](http://www.ponylang.org/papers/fast-cheap.pdf)があります。ScalaやErlang、Rustといった言語との比較も載っています。
* メモリセーフ
    * ダングリングポインタやバッファーオーバーフローが無いのはもちろん、nullも許容されません。
* 例外安全
    * 実行時例外はなく、例外は全てハンドルされることが保証されます。
* データ競合フリー
    * ロックやアトミック演算のようなものはありません。代わりにデータ競合が起きないことをコンパイル時に保証してくれる仕組みがあります。
* デッドロックフリー
    * そもそもロックがないのでデッドロックがありません。

[公式](http://tutorial.ponylang.org/)では上の5つをまとめて `capabilities-secure` と呼んでいます。
並行処理にかぎらず普通のプログラミングにおいてもデバッグしにくかったり再現性のないバグを生み出しそうな要素をできるだけ言語から排除していることが分かります。

その他の特徴としては

* コンパイルされる
    * インタプリタやVM無し
* C/C++との親和性
   * C言語のライブラリを呼べる
   * Cのヘッダを生成できるのでC/C++からPonyのコードを呼べる

などが挙げられています。

またErlang, Scalaより高速に動作するという[ベンチマーク](http://www.ponylang.org/benchmarks_all.pdf)の結果もあります。

# 文法つまみ食い

ここからは[チュートリアル](http://tutorial.ponylang.org/)にあるPonyの機能を見ていきます。以下で紹介するコードは [公式サンドボックス](http://sandbox.ponylang.org/)で試すことが出来ます。また、Mac OSXでは`brew install ponyc`でponyコンパイラをインストールすることができます。

## ハローワールド

サンドボックスに以下のコードを入力してRunを押すと結果が表示されます。

```scala
actor Main
  new create(env: Env) =>
    env.out.print("Hello, world!")
```

`class Foo` でClassが宣言できるのと同じように`actor Foo`のようにActorが宣言できます。
`new Bar()`とするとコンストラクタの宣言ができます。

## Actor

Main自体もActorでしたが、もう少しActorについて見ていきましょう。

ここでは公式リポジトリのサンプルから[counter](https://github.com/CausalityLtd/ponyc/blob/master/examples/counter/main.pony)を見ていきます。（説明のため若干変更しています）

```scala
use "collections"

actor Counter
  var _count: U32
  
  new create(c: U32) =>
    _count = c
    
  be add(c: U32) =>
    _count = _count + c
    
  be get_and_reset(main: Main) =>
    main.display(_count)
    _count = 0

actor Main
  let env: Env

  new create(env': Env) =>
    env = env'

    let count: U32 = 10
    let counter = Counter(5)

    for i in Range[U32](0, count) do
      counter.add(1)
    end

    counter.get_and_reset(this)

  be display(result: U32) =>
    env.out.print(result.string())
```

上記のコードを実行すると、counterが５から始まり、10回`add(1)`が呼ばれた後、`15`が出力されます。
なんとなくコードを眺めるだけでも大体の処理が追えるのではないでしょうか？
いくつか面白そうな点を説明すると、

- actorの受け取るメッセージ(behavior)は`be`というキーワードで定義できます。
- behaviorではメソッド宣言のように型を宣言できます。一方、返り値の型は定義できません。
- behaviorはメソッドのように呼び出すことが出来ます。処理は非同期に行われるためブロックされません。
- `'`が変数名で使えるので、`env = env'`のような書き方が可能になっています。
- 数値の型がU32など、厳密に定められています。

などが挙げられます。

behaviorがメソッドと同じように宣言できるので、存在しないbehaviorの呼び出しをコンパイル時に検出することが出来ます。また、メソッドと同じように引数に型をつけることができるなど、クラスもアクターも同じような感覚で扱うことが出来るようになっています。

## Reference capabilities

Ponyで一番特徴的だと思われるReference capabilities(C/C++のconstのようなもの）の説明に入ります。
Ponyでは`String ref`とするとmutableなStringの変数を、`String val`とするとimmutableなStringの変数を宣言することが出来ます。
Ponyでは、このような修飾子をコンパイル時にチェックすることによって、ロックのような仕組みを使うこと無くデータ競合の危険性を排除することができます。また、ロックを使わないので結果的にデッドロック問題も回避できます。

コードで見てみましょう。
例として単純にStringをprintするだけのサンプルを見ていきます。

```scala
actor Main
  new create(env: Env) =>
    let s_val: String val = "test val"
    env.out.print(s_val)
```

s_valは`String val`、つまりimmutableなので当然ながら以下はコンパイルエラーです。

```scala
actor Main
  new create(env: Env) =>
    let s_val: String val = "test val"
    s_val.append("pony")
```

```scala
/ponyc/webcontainer/main.pony:4:17: receiver capability is not a subtype of method capability
    s_val.append("pony")
                ^
/ponyc/webcontainer/main.pony:4:5: receiver type: String val
    s_val.append("pony")
    ^
/ponyc/packages/builtin/string.pony:576:3: target type: String ref
  fun ref append(seq: ReadSeq[U8], offset: U64 = 0, len: U64 = -1): String ref^
  ^
```

エラーメッセージが難しそうですが少し見てみましょう。
まず`s_val`は`String val`と宣言されているのでimmutableです。
次に、最後のエラーメッセージを見ると`append`メソッドは
`fun ref append ~~~`のように定義されているようです。
まず`fun`はメソッド宣言を表します。
そして、メソッドの宣言時に`fun ref`と書くとメソッドレシーバーが`ref`の時のみ実行できるメソッドを作ることが出来ます。
つまりレシーバーが`ref`のときにだけ使えるメソッドが`val`で呼ばれたからエラーになったということです。

次に`ref`を見ていきましょう。

```scala
actor Main
  new create(env: Env) =>
    let s_from_ref: String val = recover
      let temp: String ref = String()
      temp.append("test ref")
    end
    env.out.print(s_from_ref)
```

recoverってなんだ？と思われるかもしれませんが今のところrefな変数をvalに変換するものだと思ってください。[^recover]

[^recover]: 詳しくは http://tutorial.ponylang.org/capabilities/recovering-capabilities/ で紹介されています。

`temp`が`String ref`なので`temp.append()`としてもエラーになりませんでした。
そして、一通りmutableとして書き換えが終わったら`recover`の効果で`ref`が`val`に変換されます。

`temp`も`s_from_ref`も`String`としては同じ型ですが、先ほどの`fun ref`の仕組みによって、immutableにした後に間違えて`append`を呼んでしまう恐れはありません。また、このような仕組みがあるため`ImmutableString`と`MutableString`のような二通りのクラスを作成する必要もありません。[^need]

[^need]: Stringのような一般的なものであれば2つ作ることはそこまで苦ではないと思いますが、自作のそこまで一般的ではないクラスに対してmutable版, immutable版の2つを作り変換関数を一つ一つに対して書くのは少し大変だと思います。

ちなみに下記のコードのように`print`メソッドに`String ref`を渡すとコンパイルエラーになります。

```scala
actor Main
  new create(env: Env) =>
    let s_ref: String ref = String()
    s_ref.append("test ref")
    env.out.print(s_ref)
```

```scala
/ponyc/webcontainer/main.pony:5:19: argument not a subtype of parameter
    env.out.print(s_ref)
                  ^
/ponyc/packages/builtin/stdstream.pony:58:12: parameter type: Bytes val
  be print(data: Bytes) =>
           ^
/ponyc/webcontainer/main.pony:5:19: argument type: String ref
    env.out.print(s_ref)
                  ^
```

`env.out.print()` は `val` でないと受け取ってくれない。つまりimmutableでないと処理してくれないことがエラーメッセージから分かります。先程はメソッドレシーバーの制約でしたが今度は引数の制約です。また、先程はmutable(書き換え可能)でないとコンパイルエラーだったのに対し今回はimmutable(書き換え不可能)でないとコンパイルエラーでした。

このようにPonyではあるメソッドが、どのような条件で動くのかを細かく指定することが出来ます。
条件に適合したプログラムを書くのが大変な時もありますが、複数のアクターが協調動作する場合には、
どのデータなら安全に他のアクターに渡すことが出来るか？どのデータを渡すと危険になってしまうのか？といった判断をコンパイラに委ねる事ができるので安心してロジック部分の記述に集中することが出来ます。

このような違いを持つReference capabilitiesが `iso`, `val`, `ref`, `box`, `trn`, `tag` の合計６個存在し、subtype関係なども定義されています。
今回は分かりやすい`ref`と`val`のみを紹介しましたので「それRustにもあるよ！」というツッコミが来そうですが、
Ponyでは残りの４つも駆使しながらよりActorに特化した安全性を提供しています。[^rust]
詳しくは公式の該当するページ(http://tutorial.ponylang.org/capabilities/reference-capabilities/) をご覧ください。

[^rust]: 例えばRustではデッドロックのリスクをコンパイルの時点では排除しきれません。PonyではアクターやReference capabilitiesの力を活用し、ロックを使わなくても並行処理を行えるようにしているためデッドロックのリスクが原理的に存在しません。もちろん逆にPonyにはできなくてRustにはできることもたくさんあるので、RustよりPonyの方が優れているという主張ではありません。（例えばPonyはGCを利用しますが、Rustにはより洗練されたメモリ解放の仕組みがあります。）２つの言語は異なる利点と欠点を持ち、得意なところが違うという点をご了承頂ければと思います。

## まとめ

以上でPonylangの紹介は終わりです。
今回はReference capabilitiesによってmutable, immutableを使い分けることを中心に説明しました。
そもそもmutableなんて使わないよ！みたいな方も居ると思いますが、Ponyにはnullを許さないメモリ安全性やデッドロックの心配がないデッドロックフリーなどの魅力的な性質がまだまだあるので、immutableガチ勢の方にもきっと満足いただけると思います。[^article]

[^article]: なぜActorモデルにshared memory方式を入れて、参照ごとに値のread/writeが安全かどうか保証したいのか。Actorはshared nothingなのが売りなのでは？と疑問に思われた方は上で紹介した論文( http://www.ponylang.org/papers/fast-cheap.pdf ) のintroduction部分を読むと少し納得が行くと思うのでぜひご覧ください。

たまにコンパイルエラーが人智を越えた領域に到達したりしますが、[CausalityLtd/ponyc](https://github.com/CausalityLtd/ponyc)にて、改善・改良が現在進行形で進められています。

仕事でいますぐ使えるか？と言われるとまだ少しだけ早いような気がします[^work]が、ponyのcapabilities-secureの概念を学んでおけば、他の言語でActorを使ったプログラミングをする際に、ここはboxっぽいなとかここはisoっぽいな、などといった新しい視点が得られると思います。
他の言語ではコンパイル時にコードが`capabilities-secure`かどうかのチェックを受けることはできませんが、動的型付け言語を書くときも静的型付け言語の経験が役に立つ[^dynamic]のと同じようにPonyの`capabilities-secure`の概念を学んだ経験が、他のプログラミング言語を書くときにも役立つといいなーと思っています。

[^work]: コンパイラの枯れ具合・標準ライブラリの充実度・パッケージマネージャの存在・APIドキュメントの充実などまだまだ色々な発展が必要そうです。

[^dynamic]: あるいは逆に静的型付け言語での経験が動的型付け言語を書くときに役立つように

この記事をきっかけにちょっと勉強してみようかなーと思った方はぜひ[公式チュートリアル](http://tutorial.ponylang.org/)を試してみてください。とても分かりやすいですが、途中でページの内容が空になってて「なるほど〜」という気分になれます。（この辺は新しい言語なので仕方ありません。ガンガン使ってガンガンフィードバックしていくもよし、話題だけウォッチしておくのもよしです。）

ということでPonylangの紹介は終わりです。
明日は[@nyamngo](https://twitter.com/nyamngo)さんの「シェルスクリプトで型無しデンジャラス生活」です。