北海道苫小牧市出身の初老PGが書くブログ

永遠のプログラマを夢見る、苫小牧市出身のおじさんのちらしの裏

定数の書き換え

定数は書き換えられないから定数なのですが。


perlの定数はサブルーチンとして実装されてるので、サブルーチンを定義し直せば変更できちゃったりします。ただし、普通にやると、

Constant subroutine main::HOGE redefined at constant_test.pl line 10.


と言われます。これをperldiagで見ると、(S)*1となっているので、no warningsで制御できなさそうです。そこで、(W)*2 で定義されている "Constant subroutine %s undefined" であれば止められそうなので、一度定数サブルーチンをundefしてから再定義することにします。


できたコードはこちら。

use strict;
use constant HOGE => 1;

print "&HOGE=", &HOGE, "?n";
print " HOGE=", HOGE, "?n";

{
        # 定数HOGEを2に書き換えます
        no warnings qw{misc};
        undef &HOGE;
        *HOGE = sub () {2};
}

print "&HOGE=", &HOGE, "?n";
print " HOGE=", HOGE, "?n";


ところがまだ罠が。これを動かすと以下のようになります。

&HOGE=1
 HOGE=1
&HOGE=2
 HOGE=1


書き変わってない定数がありますorz。perlsubによると、オプティマイズによって定数と見なされたサブルーチンが&なしで呼ばれると、インライン展開されるようです。つまり、HOGEで呼び出してる箇所はコンパイル時にインライン展開されているので、その後にHOGEの値を書き換えても手遅れってことになります。


まとめ。「定数は、&をつけて呼び出してる場合に限り、no warningsしてundefして再定義すれば書き換え可能。」

*1:severe warning

*2:warning