2018年のCrystalコンパイラ振り返り

この記事はCrystal Advent Calendar 2018の1日目です。え？　今日は12/5だって？
うるせー、知らねー、Crystal Advent Cale
ndar 2018

あまりに盛り上がらなくて寂しいので書いていきます。

# まえがき

2018年が始まった当初はバージョンが0.24.1だったCrystalも、12月現在ではバージョン0.27.0までリリースされ、様々な変化がありました。

構文の追加や、それに伴う標準ライブラリの拡充などなど。

それらを[CHANGELOG.md](https://github.com/crystal-lang/crystal/blob/9c42d31daf1331e31ba2c07679571acea699fa7a/CHANGELOG.md)から拾いつつ説明していきたいと思います。

# バージョン

## 0.24.2 (2018-03-08)

記念すべき2018年初のリリースです。

このバージョンはパッチバージョンしか上がっていないことからも分かるように、後方互換性のある変更しか入っていません。

強いて上げるなら面白い変更としては`skip_file`というマクロが新しく追加されたことでしょうか。
これは名前の通り、呼び出されるとそのファイルのコンパイルをスキップするというマクロです。これを使うと、特定の環境のみでコンパイルされてほしいようなソースコードがあるときに、従来ならその部分を丸ごとマクロの`if`で囲っていたものを、ファイルに切り出して、そのファイルを早々に`skip_file`する、ということができます。

例えば、このようにファイルがあったとすると、`Foo.foo`はDarwin (macOS)向けにコンパイルした場合`:darwin`を返して、Linuxの場合は`:linux`を返すメソッドとして定義されて、それ以外の場合は`Foo.foo`は定義されなくなります。

```console
$ tree src
src
├── env
│   ├── foo_darwin.cr
│   └── foo_linux.cr
└── foo.cr

1 directory, 3 files
```

```ruby:src/foo.cr
module Foo
end

require "./env/*"
```

```ruby:src/env/foo_darwin.cr
{% skip_file unless flag?(:darwin) %}

module Foo
  def self.foo
    :darwin
  end
end
```

```ruby:src/env/foo_linux.cr
{% skip_file unless flag?(:linux) %}

module Foo
  def self.foo
    :linux
  end
end
```

## 0.25.0 (2018-06-11)

2018年最初のマイナーバージョンの上がったリリースです。Semantic Versioningでは`0.x.x`台のバージョンは、後方互換性に影響のあるリリースでマイナーバージョンを上げるらしいので、ここではいくつかbreaking changeがあります。

しかしbreaking changeと言っても基本的にはそこまで影響があるものではなくて、例えば`shards`コマンドへのエイリアスだった`crystal deps`コマンドが削除されたり、`loop`メソッドのブロックにカウンタが渡されなくなったりしたことで影響を受ける人は少ないでしょう。

特徴的な変更点としてはヒアドキュメントの実装が見直されて、Rubyやシェルスクリプトと同様に、一行に複数のヒアドキュメントを置いたり、ヒアドキュメントからメソッドを続けたりできるようになりました。
これによって、このようなQuineが書けるようになりました。

```ruby
puts (<<-'String'+"\n")*2, String
puts (<<-'String'+"\n")*2, String
String
```

よく分かんないけどなんかすごいですね。ちなみに、諸事情でstring interpolationの中ではヒアドキュメントは使えません。いや、誰か実装してくれたらいいんだけど、そもそも何が正しい仕様なのか分かんないよね‥‥。

加えて、ユーザーがアノテーションを新しく定義して、マクロから参照できるようになりました。

```ruby
annotation FooAnn
end

@[FooAnn(value: 42)]
class Foo
end

pp {{ Foo.annotation(FooAnn)[:value] }} # => 42
```

いくつかのライブラリではこのアノテーションを使って、いい感じのシンタックスを提供していたりします。その辺の紹介が今後Crystal Advent Calendarであるといいですね。
標準ライブラリでも`JSON::Serializable`や`YAML::Serializable`というものが追加されて、アノテーションを使ってJSONやYAMLにシリアライズされるオブジェクトを楽に書くことができるようになりました。その辺の紹介も(略。

あと`{% verbatim do %}...{% end %}`という構文が追加されたり、色々ありました。

他にもバグ修正とかメソッドの追加とかがあります。詳しくはCHANGELOG.mdを見てください。

## 0.25.1 (2018-06-27)

0.25.0の二週間後くらいにリリースされたバージョンです。

このリリースがバグ修正ばかりでそんなに面白い変更は無い気がします。

## 0.26.0 (2018-08-09)

二度目の後方互換性に影響のあるリリースです。

が、このリリースはそこまで大きな変更は無いかと思います。
というのも、このリリースではパーサーが新しい演算子(`//`, `&+`, `&-`, `&*`, `&**`)をパースできるようになったりしましたが、それらの実装は加えられていなかったり、全体的に大きな変更のための準備をしている感が強いからです。

細かな修正や変更ばかりで面白そうなのが無いので飛ばします。

## 0.26.1 (2018-08-27)

0.26.0のマイナーチェンジです。マイナーチェンジなのに一番上に**(breaking-change)**ってマークされてる変更点が上げられてるのが面白いですね。これに関しては色々あったような気がするのですが、語るほどは覚えていないです。破壊的ではあるけど、現実的にはほとんど問題ないと思います。

## 0.27.0 (2018-11-02)

三度目のbreaking changeのあるリリースです。
そして、現状の最新版です。

これはそれなりに大きな変更のあるバージョンだと思います。

まず、0.26.0で追加された演算子に対して実装が追加されました。

`&+`, `&-`, `&*`という演算子は、これまでの`+`, `-`, `*`と同様の振舞いをします。

```ruby
1 &+ 2 # => 3
1 &- 2 # => -1
1 &* 2 # => 2
```

そして、現在はまだ導入されていませんが、次のバージョン(0.28.0)以降は、従来の`+`, `-`, `*`の挙動が変わって、オーバーフローをチェックするようになります。

```ruby
Int32.MAX + 1 # raises OverflowError ?
Int32.MIN - 1 # raises OverflowError ?
Int32.MAX * 2 # raises OverflowError ?
```

これは地味に大きな変更だと思うので気を付けた方がいいかもしれません。

あまり詳しくないんですが、Swiftとかもこんな感じなんでしょうか？

(参考: [crystal-lang/crystal#6223](https://github.com/crystal-lang/crystal/pull/6223))

`//`という演算子は、計算結果が`floor`で丸めこまれる`/`になりました。これは整数を浮動小数点数で割っても整数のままにしたいときに使えます。

```python
10 / 3.0 # => 3.33333333...
10 // 3  # => 3
```

確かこれはPythonと同じだった気がします。ちょっと自信がありません。

他にも`Hash#dig`が追加されたり、色々便利になっています。

# まとめ

この一年、Crystalのコンパイラがものすごく進化したというわけではありませんが、着実に成長しているということを感じてもらえたら幸いです。
また、そこまで大きな変更が無いのも、Crystalが安定しつつある証左となるかもしれません。

あまり語りませんでしたがWindowsサポートやマルチスレッド対応も着実に進んでおり、2018年の頭には希望も無かった1.0.0への道も少しづつ明くなってきているのではないかと思います。

Crystalに興味を持ってもらえたら嬉しい限りです。

さてそれでは、この長い記事を最後まで読んでいただきありがとうございました。

あとCrystal Advent Calendarは執筆者を募集中です。というか足りなくてヤバい。頼む!!!