Mobile Factory Tech Blog

技術好きな方へ!モバイルファクトリーのエンジニアたちが楽しい技術話をお届けします!

!!0 eq 0 ? 'True' : 'False'の結果は?|Perlのコンテキストとスカラ値を覗く

Falseになります。

なぜか?

eqは何か?

 eqは、文字列同士が一致しているか確かめる演算子です。より詳しく言えば、SV(Scalar Value/スカラ値)という構造体の中のPV(Pointer Value/文字列)を比較します*1。スカラ値の文字列を利用することを、Perlならではの用語で言えば「値を文字列コンテキストで評価する」と言います。

 Perl以外の言語では、値が一致するか比較する演算子は==だけが用意され、文字列同士で比較したいなら、a.toString == b.toStringのように明示的に値を変換したりします。Perlの場合、数値として比較したいならば、==を使い、文字列として比較したいならば、eqを用います。eqを使った場合、値は暗黙的に文字列として評価された値同士で比較されます。

 こういった演算子に呼応し暗黙的に値が変わる背景は、作者のLarry Wall氏が自然言語のようにPerlをした言語設計したことが背景にあります。私なりに解釈で例え話をすると、例えば子供が「牛乳!」と叫んでいれば、親としては「牛乳がほしい」と読み取れると思います*2。日常のコミュニケーションでは、コンテキスト次第で伝えた文字以上の情報を受け取れます。これは慣れた人同士でのコミュニケーションを円滑にします。一方、知らない人とのやりとりでは、曖昧さを生みます。

!!0は何か?

 !は否定演算子です。!を2つ重ねることで、元の値を真偽値としてみなした値となります。banban演算子と呼ばれ、真偽値を表現したい時に使い、!!0であれば、Falseを表現しています*3

 Devel::Peekで!!0のperl内部の状態を詳しくみてみましょう。

➜ perl -MDevel::Peek -e 'Dump !!0'
SV = PVNV(0x7fd3a58097f0) at 0x10f94d560
  REFCNT = 2147483645
  FLAGS = (IOK,NOK,POK,READONLY,PROTECT,pIOK,pNOK,pPOK)
  IV = 0
  NV = 0
  PV = 0x10f91e415 "" # ←ここに注目
  CUR = 0
  LEN = 0

 PVに注目してください。PV = 0x10f91e415 ""の意味は、アドレス0x10f91e415に、空文字""が格納されているという意味です。

 この!!0は何も特別な値ではなく、例えば、2<1といった数値の大小比較の結果など偽を返す条件式の返り値と同じ値になります。

➜ perl -MDevel::Peek -e 'Dump 2<1'
SV = PVNV(0x12600a7f0) at 0x126008958
  REFCNT = 2147483647
  FLAGS = (IOK,NOK,POK,READONLY,PROTECT,pIOK,pNOK,pPOK)
  IV = 0
  NV = 0
  PV = 0x102ef6759 ""
  CUR = 0
  LEN = 0

!!0 eq 0の正体

 !!0 eq 0は、文字列の等価演算子eqを用いているので、!!00を文字列コンテキストで評価します。文字列として評価すると、!!0は空文字""0は文字列"0"となります。空文字""と文字列"0"は値が一致しないので、!!0 eq 0の結果はFalseとなります。

*1:https://github.com/Perl/perl5/blob/d49261a994af573600a092db8e91dea2459b9f8a/sv.c#L7908-L7910

*2:親としては、「牛乳!」だけでなく何をしてほしいかちゃんと話してほしいところですが

*3:perl5.36から導入されたbuiltin::falseと、!!0は一致します