01. はじめに

この本はプログラミング言語 Crystal の入門書です。おそらくまとまった一冊の書籍としては世界初の初心者向け Crystal 本になっています。

Crystal が登場したのは2014年のことで、それからずっと「 Fast as C, Slick as Ruby 」というコンセプトで作られています。

つまり Crystal は、

  • C 言語の速さ

  • Ruby の書き味

を同時に持つ実用的なプログラミング言語を目指して開発されています。元々は Manas Technology Solutions 社によって2011年から開発されていましたが、現在はオープンソースのプロジェクトとして公開され有志の手によって精力的に開発が進んでいます。そして、とうとうバージョン1.0のリリースが見えてくるところまで完成度が高くなりました。

このように Crystal は新しいプログラミング言語ですので、本書を手に取っていただいた方の中には Crystal というプログラミング言語について初めて知ったという方もいるかもしれません。そこで、このはじまりの章では Crystal の特徴について概要を簡単に紹介していきます。

ただ、どのようなプログラミング言語かということに関しては、言葉で説明するよりもまず実際のプログラムを見てイメージをつかんでもらう方が早いですよね。次のプログラムは、Crystal でごくシンプルな HTTP サーバを実装したプログラムです。

require "http/server"

server = HTTP::Server.new do |context|
  context.response.content_type = "text/plain"
  context.response.print "Hello world, got #{context.request.path}!"
end

puts "Listening on http://127.0.0.1:8080"
server.listen(8080)

いかがでしょうか。プログラムの細かいところはまだわからなくて問題ありませんが、Ruby を使ったことがある方であれば Crystal のプログラムが一見してとても Ruby に似ていることに気づいたと思います。自ら「 Slick as Ruby 」と称していることからもわかるように、Crystal は Ruby にとてもよく似たシンタックスを持ったプログラミング言語です。しかし、Crystal は Ruby とは異なる独自の特徴をいくつも持っており、それによって「 Fast as C 」の高速性や型安全なプログラミングを実現しています。 

ここから、その Crystal の特徴を簡単にお伝えしていきます。

コンパイラ言語 Crystal

Crystal の処理系はコンパイラとして提供されます。このことはつまり、Crystal のプログラムを実行するには、Crystal コンパイラでソースコードをコンパイルし実行ファイルを生成する必要があることを示しています。これは類似したシンタックスを持つ Ruby がコンパイル不要なインタプリタ型言語として作られていることとは対照的です。

Note
より正確に言うと、Ruby も実行する際に内部的にコンパイル処理を行なっているのですが、ここでは話を単純にするために実質的にインタプリタ型言語と分類しています

Crystal はコンパイラ型の言語となっていることで、実行時速度の高速化や次項でお伝えする静的な型システムを実現しています。

また、コンパイルすることで直接実行できるファイルが生成されるので、実行する環境に処理系を用意する必要がなくアプリケーションのデプロイが容易なことも利点の1つです。なお、本書では詳細には触れませんが、Crystal はコンパイラ基盤に LLVM を利用しており、各プラットフォームに最適化した実行ファイルの生成が可能になっています。

Crystal の型システム

Crystal は静的型付けのプログラミング言語です。これも、動的型付け言語の Ruby とは異なった Crystal の大きな特徴です。

プログラムの中でデータの型は静的に解析されチェックが行われます。このことによって、型の不一致などはコンパイル時に補足され、実行時にエラーになってしまうことを防止できます。

ただ、Crystal は強力な型推論の仕組みを備えているため、多くの場合はプログラマが自分で面倒な型指定をしなくてもよいようになっています。

例えば、次の簡単なプログラムを見てください。

def shout(x)
  # Int32 と String はどちらも `to_s` メソッドを持っている
  x.to_s.upcase
end

foo = ENV["FOO"]? || 10

typeof(foo)        # => (Int32 | String)
typeof(shout(foo)) # => String

このプログラムは、変数 foo に、

  • 環境変数 FOO が存在すればその値の文字列(String 型)

  • 存在しなければ 10 という数値(Int32 型)

を代入し、foo の型と shout(foo) の型を typeof によって調査するものです。shout メソッドの中では、引数として渡されたデータを to_supcase というメソッドによって大文字の文字列に変換しています。このとき、 StringInt32 もどちらも to_s という文字列変換メソッドを持っていることがコンパイラによって正しく推論されるため、型を指定していなくてもエラーにはなりません。続いて typeof の結果を見てみましょう。foo の型は実行時まで StringInt32 かが判定できないために両方の複合型(ユニオン型)になっています。一方、 shout(foo) は戻り値の型から String だということが保証されるため、その型も String として正しく推論されていることがわかります。

Null 安全性

「 Null 参照によるエラーの損害は10億ドル相当だ」という有名な言葉を聞いたことがある人は多いと思います。

実際にプログラミングをしていても、おそらくほとんどの人が Null に 対して何か操作しようとしてエラーになってつらい経験をしたことがあるのではないでしょうか。Java の NullPointerException などはよく話のネタになりますよね。

そこで、最近のモダンなプログラミング言語は Null 安全性を取り入れているものが多くなってきており、Crystal も例外ではありません。

次のプログラムを見てください。

hello_world.cr
if rand(2) > 0
  my_string = "hello world"
end

puts my_string.upcase

これは、rand メソッドによって 02 を生成し、その結果によって if 条件を判定しているものです。しかし、実行するまでその結果が「真」になるかどうかはわかりません。したがって、my_string が Null でないことをコンパイル時に保証することはできません。この場合は upcase メソッドが呼び出せるかどうかがわからないため、コンパイルは以下のようなエラーになります。

$ crystal hello_world.cr
Error in hello_world.cr:5: undefined method 'upcase' for Nil (compile-time type is (String | Nil))

puts my_string.upcase
               ^~~~~~

このようにして、Crystal では Null 安全性を保証しており、また、Null でない場合だけに実行する処理の記述なども書きやすい設計となっています。

マクロ

先述したように、Crystal は静的型付けのコンパイラ言語であり、それによって安全なプログラムの構築が可能になっています。その一方で Ruby のような動的型付け言語が得意な「実行時にプログラムの動作を変える」こと、いわゆるメタプログラミングや実行時リフレクションといったテクニックは制限されます。

しかし Crystal には強力なマクロの仕組みが搭載されており、それを活用することでかなり自由度の高いプログラムを書くことが可能です。

マクロについては後の章で詳しく触れます。

Crystal の並行処理

現在のプログラミングにおける大きな変化として、並行処理や並列処理が高い注目を集めるようになったことがあげられるでしょう。進化した並列処理の機構を特徴とする Rust や Go 言語、そして非同期処理によってシェアを伸ばした Node.js を見ても、プログラミング言語に並行処理は欠かせないものとなっています。

本書では大きく触れませんが、Crystal では、ノン・プリエンプティブな軽量スレッドを使った並行処理が可能になっており、それをファイバーと呼んでいます。ファイバー間におけるデータのやり取りには Go 言語や Clojure のようにチャンネルを利用し、共有メモリやロックを意識しなくても使いやすいように設計されています。

C バインディング

本書の範囲を超えてしまうので詳細は触れませんが、Crystal は C 言語ライブラリのバインディングを書きやすいので、C 言語の資産を Crystal から利用することも難しくありません。

パッケージ管理

現代的なプログラミングでは OSS などで提供されるライブラリをいくつも利用することがごく一般的ですが、数が多くなってくるとその依存関係を管理するのがとても大変になります。したがって、パッケージングのシステムがあるかどうかはプログラミング言語の利用しやすさにおいて大きな位置を占めています。

Crystal には Shards というパッケージ管理のシステムがあります。この Shards についても後の章で詳しく触れます。

Crystal のコミュニティ

プログラミング言語を使うときには、その言語自体の仕様はもちろんですが、その言語コミュニティが充実していることも同じくらい大事ですよね。ここでは、Crystal のコミュニティや公式の一次情報を得るためのサイトを紹介します。

Crystal 公式サイト(英語)

https://crystal-lang.org
Crystal の公式サイトです。リリースノートやブログ、そして API ドキュメントがあります。英語ですが、基本的には一次情報はこのサイトを中心として見ていれば得ることができます。

Crystal の Google グループ (英語)

https://groups.google.com/forum/#!forum/crystal-lang
Crystal に関することで何かあれば、まずこの Google グループに書き込むことが推奨されています。例えば Crystal に関する質問や Crystal を使ったプロジェクトの紹介など、Crystal に関することであれば何でも OK です。活発にやりとりが行われています。

Gitter の Crystal 公式チャットルーム(英語)

https://gitter.im/crystal-lang/crystal
Crystal に関する Gitter の公式チャットルームです。チャットなので Google グループより気軽に質問などができて、レスポンスも早いことが期待できます。こちらもとても活発で、IRC との連携もされています。

Crystal の GitHub リポジトリ

https://github.com/crystal-lang/crystal
Crystal の開発は GitHub 上で行われています。Crystal の不具合を見つけたときに issues に報告したり、何か素晴らしい新機能や修正について直接 pull request を送ることもできます。

Crystal-JP の Slack(日本語)

http://crystal.pine.moe
日本の Crystal ユーザコミュニティ「 Crystal-JP 」の Slack への招待ページです。Crystal-JP の Slack では日本語で Crystal の情報交換を行うことができます。お気軽に参加ください。また、Crystal-JP では不定期に(今のところ東京のみですが)イベントを開催しており、そのお知らせなども主にこの Slack で告知されます。

また、Crystal のライブラリなどを探したい場合には Awesome CrystalCrystalShards が参考になるでしょう。

まとめ

本章では、Crystal の特徴を簡単に説明しました。Crystal がどのようにして「 C 言語のように速く、Ruby の書き味を持つ」ということを実現しているかの概要だけでも把握していただき、Crystal の魅力を感じていただけたら幸いです。

次の章からはより実践的な Crystal のプログラミングについて説明していきます。

最後になりますが、本書で利用している Crystal のバージョンは執筆時点で最新の 0.26.1 です。異なるバージョンの Crystal では掲載されているプログラムが期待通りに動作しない可能性もあります。予めご了承ください。