LoginSignup
11
10

More than 5 years have passed since last update.

括弧なんて省略できらぁっ!って人へ

Last updated at Posted at 2016-08-26

こりゃあ面白いRubyistだぜ

こりゃあどうしても括弧を使わずにプログラムを書いてもらおう。

タイトルは煽りです。括弧を使わずに書くことに慣れすぎて思わぬところで意図しない結果になってしまうというdefined?の注意点を書きます。

if defined? foo && foo.is_a? Array
    p 'true'
else
    p 'false'
end

さて、これを実行するとどうなるか・・・?

fooが定義されてない時点でdefined?nilを返すから"false"が出力されるに決まってらぁ!

そうはいかないぜ食いしんぼうさん。これはsyntax errorになります。なぜかは後で説明しますがsyntax errorを解消するにはis_a?の引数を括弧で囲ってあげます。

if defined? foo && foo.is_a?(Array)
    p 'true'
else
    p 'false'
end

さて、これを実行するとどうなるか。

fooが定義されてない時点でdefined?nilを返すから"false"が出力されるに決まってらぁ!

いいえ、違います。
実はこれ"true"が出力されます。

defined?についておさらいすると、defined?は定義されていない式を与えるとnilを返します。定義されている場合は評価した式の種別を文字列で返します。trueではありません文字列です。文字列がtrueとして評価されるだけです。

例えばdefined? fooを実行するとfooが定義されていなければnil, fooが定義されていれば"local-variable"を返します。

さてなぜこのような結果になるかというとdefined? foo && foo.is_a?(Array)は括弧がないためfooではなくfoo && foo.is_a?(Array)を評価していることになるからです。

つまりfooという変数が定義されているかではなくfoo && foo.is_a?(Array)という式が定義されているか意味になり、これはfooが定義されているかどうかに関わらずnilでなく"expression"を返します。
※式が定義されているかという言葉を使いましたがdefined?にどんな式を与えても"expression"を返すようです。

これでなぜif defined? foo && foo.is_a? Arrayがsyntax errorになるかわかりましたね。foo && foo.is_a? Arrayという式は正しいRubyの書き方ではないからです。

ですのでこのように括弧を使えば意図したとおりの結果になります。

if defined?(foo) && foo.is_a?(Array)
    p 'true'
else
    p 'false'
end

ついでなのでもう一点罠を

if false
    foo = []
end

if defined? foo
    p 'true'
else
    p 'false'
end

さて、これを実行するとどうなるか。

iffalseに固定されていてfooに配列が代入されることはあり得ないから、定義されていない変数foodefined?で評価するとnilを返し"false"が出力されるに決まってらぁ!

違います。実はこれも"true"が出力されます。fooへの代入(ローカル変数fooの宣言)があると例えifで分岐されず[]が代入されなくてもfooは宣言済みとしてnilが入るからです。

以上、知らないとハマるdefined?の罠でした!

え!!括弧を使わずにプログラムを!?

できらぁっ!

11
10
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
11
10