Crystal - Ruby風文法を持ったコンパイル型言語
Erlang トレーニング 2013に申し込みを行った。Erlangは全く詳しくないので、トレーニングが非常に楽しみだ。新しいプログラミング言語や、新しいプログラミングパラダイムを学ぶことは楽しい。
さて、プログラミング言語にとって、ぱっと見の見た目は結構重要である。C言語系の見た目であるC++/Java/PHPなどは、C言語を知っていれば違和感を覚えにくい。
今回紹介するプログラミング言語の名前は、Crystalである。Ruby風の文法を持つプログラミング言語だ。つか、ほとんどRuby。アルゼンチンの会社であるmanasの支援を受けて開発されている。
Hello, world!はこちら。
puts "Hello, world!"
どうみてもRubyです(略)。ところが、以下のスクリプトはエラーが出る。
puts 'Hello, world!'
あくまで文法はRuby風、というわけ。
Crystalの実行速度
RPythonで書かれたRuby処理系であるTopazというものを以前のエントリで紹介した。そこで、MRIとTopazとの速度比較を行う一例として、セクシー素数を求めるコードを紹介した。引用すると、以下のようなコードである(Crystalのcommit 006fc13cで動作するように一部修正)。
def is_prime? n (2...n).all? { |i| n % i != 0 } end def sexy_primes n (9..n).map do |i| [i - 6, i] end.select do |i| i.all? { |j| is_prime? j } end end sexy_primes 100_000
上記セクシー素数を求めるコードを、手元のMacbook ProでRuby 2.0.0-p247とCrystalとで実行してみる。Crystalでは1.61秒。Ruby 2.0.0-p0では59.57秒。すごい速度差。それにはワケがあるわけで。
インストール方法
Ruby 1.9.3が入っているMac環境では、以下のようにしてCrystalを動作させることができる。2013年8月28日現在、いまだ.rvmrcを使っているのでrvm使いには警告が出る。また、Ruby 2.0.0-p247では動作しなかった。LLVMは3.3。
Linux環境では、libllvmが入るようなパッケージを入れればOK。
> brew install llvm --shared > git clone git://github.com/manastech/crystal.git > cd crystal > bundle > bin/crystal -e 'puts "Outsourcing!"' # ワンライナー > bin/crystal -run hello.cr # スクリプト実行
bin/crystalで実行してみると分かるが、体感として実行速度が遅いことに気づく。なぜだろうか。
Crystalの仕組み
LLVMをインストールしていたのでおわかりの方は多いと思うが、Crystalは、Ruby風の文法を解釈し、LLVM IRを生成し、それをネイティブコード化して実行している。ワンライナーの実行速度が遅いのは、そのせいだ。
よって、以下のように実行ファイルをコンパイルしておけば、動作速度は速くなる。
> bin/crystal hello.cr > ./hello
生成されたLLVM IRをのぞき見ることができる。Hello, world!だとこんな感じ。
> bin/crystal -O3 -l1 hello.cr ; ModuleID = 'Crystal' (中略) @str2 = private constant [18 x i8] c"\0D\00\00\00Hello, world!\00" define i1 @__crystal_main(i32 %argc, i8** %argv) { alloca: br label %const const: ; preds = %alloca br label %"GC::objects_size" entry: ; preds = %"const_MatchData::EMPTY" %0 = load %MatchData** @"MatchData::EMPTY" store %MatchData* %0, %MatchData** @"$~" %1 = call i1 @"*puts:Nil"(%String.0* bitcast ([18 x i8]* @str2 to %String.0*)) ret i1 %1
Crystalが目指すところ
Crystalは、ライブラリ経由でC言語の関数を呼び出しやすいように設計されている。例えばこんな感じで、sqlite3_libversion()関数を呼び出せる。
lib LibSQLite3("sqlite3") fun sqlite3_libversion : Char* end
つまり、目指すところはC言語の代替物ということらしい。
例えば、samplesディレクトリにはHTTPサーバの例がある。
#!/usr/bin/env bin/crystal -run require "socket" server = TCPServer.new(8080) puts "Listening on http://0.0.0.0:8080" while true sock = server.accept while str = sock.gets if str == "\r\n" sock.print "HTTP/1.1 200 OK\r\n" sock.print "Content-Type: text/plain\r\n" sock.print "Content-Length: 12\r\n" sock.print "\r\n" sock.print "Hello world!" sock.flush end end end
Crystalの適用領域として、HTTPサーバのようにそれなりにチューンしたいけど、Rubyの記述力も欲しいよね、といったニーズに特化しているものと予想する。
Crystalは現在セルフホスティング(CrystalでCrystalコンパイラを記述する)を目指しているようである。現在はruby-llvmを使っているはず。セルフホスティングされて、仕様も安定してきたら、それなりに高速なグルー言語としてお試ししてみたい。現在はTimeすらないし、 正規表現オブジェクトもない。正規表現オブジェクトはあった。facebookでツッコミを受けました。PCRE利用のようです。