LoginSignup
4
3

More than 5 years have passed since last update.

crystal コンパイラもサボりたくなる時

Last updated at Posted at 2015-12-01

問題

crystal のコードを試しに書いていて、早速以下のような問題にぶつかりました。

class Test
  def a
    b.new
  end
end

この a というメソッドの中では定義されていない b という変数を参照しているので java や c の感覚では当然コンパイルエラーになるはずのものです。ですが、驚いたことに実はこれはコンパイルに通ってしまいます。crystal は型チェックをしてくれるのではなかったのでしょうか?これが通ってしまっては行けないのでは?

では、実際にインスタンスを作成してみたら実行時エラーが出てしまうのでしょうか?

class Test
  def a
    b.new
  end
end
Test.new.a #=> undefined local variable or method 'b'

実はこうするとコンパイルエラーがちゃんと出ます。これは一体どういうことでしょうか?
今度はためしに Test.new.a をメソッドの中に定義して実行されないようにしてみます。

class Test
  def a
    b.new
  end
end

def c
  Test.new.a #=> OK
end

今度はまたコンパイルに通るようになりました。c をグローバルコンテキストから呼ぶとまたエラーになります。
では if false だとどうでしょうか。

class Test
  def a
    b.new
  end
end

if false
  Test.new.a #=> NG
end

これはコンパイルエラー。

では a を呼ばなかったらどうなるでしょうか?

class Test
  def a
    b.new
  end
end

Test.new #=> OK

コンパイル、通ります!

じゃあ、今度はクラスコンテキストからだと?

class Test
  def a
    b.new
  end
  Test.new.a #=> NG
end

エラー!

つまりどういうこと?

どうやら、どこからも使われていないメソッドはコンパイルの対象に含まれないようです。
グローバルコンテキストないしはクラスコンテキストからコードを再帰的に辿って行って、実際に使われているコードを洗い出してコンパイルしているのではないでしょうか。上記に書いた以外にもクラス継承を挟んでみたり、super で呼び出してみたりしましたが、実行時にメソッドが使われない場合は一貫してコンパイルスルーされました。バイナリのサイズを小さくするための工夫でしょうが、びっくりしますね。

驚いたので勢いで記事をかきました。

4
3
2

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
4
3