Crystal

前に Crystal の記事を書いて、

tmtms.hatenablog.com

このスライドの中で、

http://slide.rabbit-shocker.org/authors/tommy/crystal/28

と書いたんですが、現在は条件分岐中のメソッド定義はエラーになるようになっています。

if true
  def hoge
  end
end
% crystal hoge.cr
Error in ./hoge.cr:2: can't declare def dynamically

  def hoge
      ^~~~

これは、次の Issue で変更されたのですが、

github.com

"Seen here" で私のスライドが参照されているという…。しかもスライド公開した翌日に。 Qiita の Crystal の日本語の記事も読んでるみたいだし、Crystal 作者さんすごいな。


その後、Crystal を触ってて気づいたことなど:

インスタンス変数の型

class A
  def hoge
    @str = "hoge"
    @str + "fuga"
  end
end

A.new.hoge

これはコンパイル時にエラーになります。

/tmp% crystal hoge.cr
Error in ./hoge.cr:8: instantiating 'A#hoge()'

A.new.hoge
      ^~~~

in ./hoge.cr:4: undefined method '+' for Nil (compile-time type is String?)

    @str + "fuga"
         ^

================================================================================

Error: instance variable '@str' of A was not initialized in all of the 'initialize' methods, rendering it nilable

Specifically in these ones:

@str は明らかに文字列なのですが、initialize 内で初期化されていないインスタンス変数は nil の値を取りうるものとして扱われるためです。

initialize で初期化するか型を指定すれば問題ありません。

class A
  def initialize
    @str = "hoge"
  end
  def hoge
    @str + "fuga"
  end
end

A.new.hoge
class A
  def initialize
    @str :: String
  end
  def hoge
    @str = "hoge"
    @str + "fuga"
  end
end

A.new.hoge

.crystal ディレクトリ

crystal はコンパイル時にカレントディレクトリに .crystal というディレクトリを作ります。ソースコードの場所にかかわらず、カレントディレクトリに作ります。

気がつくとあちこちに .crystal が出来てて驚きます。

環境変数 CRYSTAL_CACHE_DIR が設定されていると、カレントディレクトリではなくその値のディレクトリを使用するようです。

自分は $HOME/.crystal を設定してあります。

シグナル処理が効かない!

次は INT シグナルを無視するプログラムですが、

Signal::INT.ignore
sleep 99999

実行すると Ctrl-C で止まってしまいます。

% crystal hoge.cr
^C
% 

ちょっと悩んだのですが、解決しました。

スクリプト言語と違って Crystal はコンパイル言語なので、crystal hgge.cr として実行した時は、実際にはコンパイルして作成されたプログラムを子プロセスとして実行しています。

なので、SIGINT で死んだのは親プロセスの crystal で hoge.cr からコンパイルされたプログラムはちゃんと SIGINT でも死なずに動いていました。

% crystal hoge.cr
^C
% ps -fe | grep hoge
tommy     5993  2190  0 00:01 pts/1    00:00:00 /home/tommy/.crystal/crystal-run-hoge.tmp
tommy     5998  3148  0 00:01 pts/1    00:00:00 grep hoge
% kill -INT 5993
% ps -fe | grep hoge
tommy     5993  2190  0 00:01 pts/1    00:00:00 /home/tommy/.crystal/crystal-run-hoge.tmp
tommy     6000  3148  0 00:01 pts/1    00:00:00 grep hoge
% kill 5993
% ps -fe | grep hoge
tommy     6002  3148  0 00:01 pts/1    00:00:00 grep hoge
% 

わかってみたら、なんだそんなことか… ってオチでした。