三項演算子と関数の罠 "Use of ?PATTERN? without explicit operator is deprecated"
$ # re.plで実行 $ sub FOO { 'FOO' } $ my $foo = FOO FOO $ $foo eq FOO ? 'foo' : 'bar' # NG Use of ?PATTERN? without explicit operator is deprecated at (eval 410) line 8. Compile error: Search pattern not terminated or ternary operator parsed as search pattern at (eval 410) line 8.
……えっ、どゆこと!?
"Use of ?PATTERN? without explicit operator is deprecated"
perldocによると*1、
perldiag - さまざまな Perl 診断メッセージ - perldoc.jpUse of ?PATTERN? without explicit operator is deprecated
(D deprecated) 一度だけマッチングする正規表現として ?\w? のようなものを 書きました。 疑問符を将来新しい演算子として利用可能とするために、この単語を直接疑問符 デリミタで始めることは非推奨となりました。 代わりに、明示的に m 演算子を使って m?\w? と書いてください: これも 疑問符デリミタは一度だけマッチングする振る舞いを起動します。
どうやら"?"記号が正規表現のデリミタ(区切り文字)として認識されたようです。
$ 'foobar' =~ /(bar)/; # 普通の場合 bar $ 'foobar' =~ ?(bar)?; # ?をデリミタとして使った場合(strictだと死亡) Use of ?PATTERN? without explicit operator is deprecated at (eval 421) line 8. bar
古いPerlでは"?"で囲うことでも一時的な正規表現を生成できたのですね。perldocを見る限りでは、5.8の時点で既に非推奨で、5.10で廃止されたようです。
perlop - Perl の演算子と優先順位 - perldoc.jp?PATTERN?
これは、reset() 演算子を呼び出すごとに 1 度だけしか マッチしないことを除いては /pattern/ による検索と全く同じです。 たとえば、ファイルの集まりの中で個々のファイルについて、 あるものを探すとき、最初の 1 つだけの存在がわかれば良いのであれば、 この機能を使って最適化をはかることができます。 現在のパッケージにローカルとなっている ?? のパターンだけが リセットされます。
なぜこのエラーが出るのか
"?PATTERN?"が廃止されたことは分かるのですが、$foo eq FOO ? 'foo' : 'bar'
で何故このエラーが出るのでしょう?
三項演算子の"?"が正規表現のデリミタとして解釈されたとしか考えられませんが、それにしても終了デリミタが無いので、正規表現と解釈されようがないように思えるのですが…。
少し実験してみます。
$ $foo eq 'FOO' ? 'foo' : 'bar' # OK foo $ $foo eq &FOO ? 'foo' : 'bar' # OK foo $ ($foo eq FOO) ? 'foo' : 'bar' # OK foo $ FOO eq $foo ? 'foo' : 'bar' #OK foo
また、FOO
にプロトタイプを付けて、完全に定数関数化することでも解決出来ました。
どうも引数を取れるサブルーチンの右に"?"が来ると挙動不審になるようです。
結論
レアケースかもしれませんが、
- 定数関数であればプロトタイプつけるか、素直にconstant.pm使う。
- 定数関数でない場合は、プロトタイプつけるのは少し抵抗があるので、比較演算子の左側にサブルーチンを持ってくるのが良さそう。
Perlのソースのlexerあたりを探れば、この問題の根幹が見つかるのかなぁ。
*1:古いバージョン(5.8とか)だとこのエラーメッセージは存在しないみたいです。