割と普通に目にするあまり、今更訊けないことって多々ありますよね。
例えば、コーヒーにウィンナーが載ってるわけじゃないのになんでウィンナーコーヒーって名前なの?とか。
ウィンナーってのはウィーン風ってことで、別にソーセージのことを指しているわけじゃないんですね。
ソーセージのほうのウィンナーも本当はウィンナーソーセージって名称で、ウィーン風ソーセージってことなんですね。
ホイップクリームのどの辺がウィーン風なのかはオーストリアの人にでも訊いてください!
……というわけで、何か記事を書けとktm@sさんから圧力を受けたのでつらつら書いていこうと思います。
いつまで続くかわからない新コーナー!「今更訊けないPerl講座」です!
記念すべき第一回目の今回は、めっちゃよく見る割に何をしてるのかよくわからない、ナゾのオマジナイと化している「or die」についてです。がんばってこのテンションについてきてください。
use perl or die
さて、or dieがよく見られるのは次のような場面ではないでしょうか。
[perl]
open(my $FN, ‘> file.log’) or die;
print $FN ‘nk. maji nullpo’;
close($FN);
[/perl]
そうですね。ファイルへの入出力を行う際にはまず必要となってくる、ファイルハンドラの作成場面です。
open関数 – 入出力に関する関数 – Perl関数のリファレンス に載っているサンプルコードにも、何の前触れもなくor die(“Error”)とありますね。
このor dieは何なのでしょうか、というお話でございます。
優先順位とは
自然言語における優先順位
何事にも優先順位というものがあります。私がこんな記事を書いているのも他にすることがないからです。
さて、自然言語(日本語とか英語とか)においても優先順位というものは存在します。
あ、すぐにPerlの話が見たければこのセクションは飛ばしてくださいね。初心者向けの解説なので身近なところから説明をしています。
で、例えば
この前買ったツボを割った。
このような文が与えられたとき、以下の二通りの解釈が考えられます。
- (いつかに)買ったツボをこの前に割った。
- (私が)割ったツボはこの前に買ったものだ。
このように多様な解釈ができる文は多義文と呼ばれます。
自然言語でこのような現象が起きるのは文字として表記されている場合が多いです。
というのも、口に出すときはどこか適切な場所で発話が区切られるからです。
で、このような文を多義的に解釈させないようにするにはどうすればよいでしょう?
そうです。読点を打てばいいんですね。
上記の解釈のそれぞれに対応するように読点を打つと、
- この前、買ったツボを割った。
- この前買ったツボを、割った。
こんな感じになります。
どこが優先順位の話になるの?ってわけですが、まあ待ってください。
どの言語でもそうですが、「副詞」と呼ばれる品詞が存在します。副詞は、形容詞や動詞、そして文を修飾するものです。上記の例では「この前」がそれに相当します。
文を修飾する副詞には基本的に結合(どの部分を修飾するか)の優先順位がありません。
つまり、上記の文では「買った」を修飾しているのか、「割った」を修飾しているのかが確定しないんですね。(ただし、「この前私は買ったツボを割った」と主語が限定的に明示されると文の範囲が限定されて結合が確定します。「この前私が買ったツボを割った」と比較してみてください。「は」は係助詞と呼ばれており、「が」の格助詞とは区別されています。限定する用法は格助詞にはありません。)
読点を打つと優先順位がない場合の結合が確定します。もちろん、句点も優先順位を確定させる記号の一つと言えるでしょう。
日本語ではこれだけ覚えておいてください。
プログラミング言語における優先順位
さて、プログラミング言語でも記号が結合の優先順位を確定させます。
いわゆるC-like言語で、日本語での句点における働きをするのがセミコロン「;」ですね。
他に必ずといっていいほど出現するのは代入演算子「=」ですね。これにも優先順位が存在します。
記号は色々あるので、それらの優先順位は Perlの演算子の優先順位(Perl5.6.1) – perldoc.jp でも眺めて確認してください。まあこのページに今回扱うor dieも出てきちゃってるのですが。
結局or dieは何をしとるのか
論理和のロジック
早くも筆者が飽きてきているのが感じられるかと思います。
私もがんばるので皆さんもがんばってついてきてください。
もう一度or dieの例文を眺めてみましょう。
[perl]
open(my $FN, ‘> file.log’) or die;
[/perl]
ぶっちゃけこの例では代入演算子がないので、例としてのインパクトはイマイチなんですけどまあいいでしょう。
orとは論理和を求める演算子です。
open関数は第一引数をファイルハンドラとして第二引数のファイルを開きます。ファイルを開くのに失敗したとき、open関数はfalseに相当する値(正確にはundefinedですが以降は面倒なのでfalseと略記します)を返します。成功したときはtrueに相当する値(同様に、以降はtrueと略記します)を返します。
論理和とは、左右のどちらかがtrueであればtrueを返すものです。どっちか片方だけがtrueであれば良いので、orの左側がtrueの場合は右側の式は処理されず飛ばされます。
というわけで、まずはorの左側が評価(処理)されます。左側はopenですね。というわけでまずopen関数が処理されます。
このとき、ファイルが正常に開ければopenはtrueを返します。orは左側を見たときにtrueであれば右側の処理は飛ばすわけですから、dieは処理されません。
ファイルが正常に開けなかったとき、openはfalseを返します。orは左側がfalseのとき、trueを返せばいいのかfalseを返せばいいのかわからないため、右側の式も評価します。つまり、右側も実行します。dieは(引数が与えられればそれをSTDERRに出力して)実行を終了する命令です。
次のように書き換えることもできます。
[perl]
my $result = open(my $FN, ‘> file.log’);
unless($result){
die;
}
[/perl]
つまり、or dieは条件分岐を伴った処理なんですね。
ちょっと待ってちょっと待っておにーさーん!
つまり、論理和は条件分岐を実装する際にも使えるヨ!というお話でした。
じゃあなんで||じゃないの?||も論理和を求める記号じゃないのサ。
ここで優先順位の話に繋がるんですね。前置きがなげーよ、バカ!!
なんで||じゃダメなの?
結論から言うとダメじゃないです。
ただ、優先順位的に「orを使うと間違いが起こりにくい」ってだけですね。
次のような例を考えてみましょう。
[perl]
open my $FN, ‘0’ || die;
[/perl]
まあまずありえない設定ですが、0という名前のファイルがあったときにこのようなコードを書いたとします。
perlの組み込み関数はパーレン(小かっこ)を省略できるため、上記のようにも書けます。
このときの処理を考えてみましょう。
openは1つ以上の引数を取ります。このような関数では複数の引数をカンマで区切って指定するのですが、この場合のカンマは右方向のリスト演算子と呼ばれます。右方向のリスト演算子は||よりも優先順位が低いため、まず’0′ || dieが評価されることになります。
‘0’が真偽評価されるときはfalse扱いになります。このあたりはCと異なるので注意が必要です。
つまり、||の左側はfalseなので、||は右側も評価します。というわけで、0という名前のファイルがあったとしても、これではファイルが開かれるより先にdieが実行されてしまうのです。
||の代わりにorが使われていたらどうでしょうか。
orは右方向のリスト演算子よりも優先順位が低いため、まずorの左側が処理されます。つまり、まずはopen関数が処理され、その返り値によってdieが実行されるかどうかが決まります。
意図したとおりに動くというわけです。
ちなみにorは代入演算子よりも低い優先順位にあります。
次のような例を考えてみましょう。
[perl]
my $var1 = &hoge() || &fuga();
my $var2 = &hoge() or &fuga();
[/perl]
||の式では、&hoge()の返り値がfalseであればfugaを実行してその返り値がvar1に代入されます。
orの式では、&hoge()の返り値がfalseであれば、var2にfalseが代入されたうえでfugaが実行されます。fugaの返り値は虚空の彼方に消え去ります。
これらを適切に使い分けられたら便利ですね。
可読性?Pythonでも使ってろ。
今回のまとめ
演算子の優先順位には気をつけよう!
適切に使い分けると便利だヨ!!
次回は制御構文の後置表記についての予定です。
コメント
>可読性?Pythonでも使ってろ。
|| より or が好まれるのは、or のほうが英語としての可読性が高いからでは。|| と or は優先順位が違うから間違いが起こりにくいという説明は、 || でも or でも優先順位が起因するバグは起こりうることを考えると、この場合の説明として適切ではないと思う。
◯◯◯ or die というのは英語でよくある表現で「命がけで◯◯◯する」というような意味で使われる。
perl は開発当初、英語としての可読性が高いことが重視されていて、perl の文法にそって詩を書くことが流行った程だった。http://www.perlmonks.org/?node_id=1111395 (20年近く前の話)
この辺りの事情は、 perl cookbook に詳しいことが書いてある。
https://www.amazon.co.jp/dp/4873110378
英語としての可読性を重視するあまり、perl の文法は極度に複雑化して、文法が原因するバグがたくさん起こるようになった。それを嫌ったユーザーがperlばなれを起こして、その後(2005〜2006ごろから) python や ruby の発展につながった。