looks_like_number()返却値の謎
前々回、前回のエントリに引き続き、looks_like_number()の返却値を調べてみた。
use Scalar::Util qw/ looks_like_number /; say looks_like_number(123); #=> 4352
1が出ると思っていたのだけれど。
もう一度perldocしてみる。
The CPAN Search Site - search.cpan.org
perldoc Scalar::Util
looks_like_number EXPR Returns true if perl thinks EXPR is a number. See "looks_like_number" in perlapi.
うわお。perlapi見てくれとな。
見てなかった。
perlapi - perldoc.perl.org
perldoc perlapi
looks_like_number Test if the content of an SV looks like a number (or is a number). "Inf" and "Infinity" are treated as numbers (so will not issue a non-numeric warning), even if your atof() doesn’t grok them. I32 looks_like_number(SV *const sv)
looks_like_number
ScalarValueの中身が数値に見えるかどうか(あるいは数値であるかどうか)をテストします。
"Inf"と"Infinity"は数値として扱われます(なので"数値でない"という警告は生じません)。
たとえatof()がそれらを把握しなくても。
で、スカラ変数一個引数にとって、32bit整数値が返却されます、ということか。
なるほどなるほど。
ていうかめちゃくちゃXSじゃん……。
というわけで改めてコードをちゃんと見てみる。
/path/Scalar/Util.pm
package Scalar::Util; # (略) require List::Util; # List::Util loads the XS # (略) unless (defined &dualvar) { # Load Pure Perl version if XS not loaded require Scalar::Util::PP; Scalar::Util::PP->import; push @EXPORT_FAIL, qw(weaken isweak dualvar isvstring set_prototype); }
あ、List::Utilからとってきてたのか。
/path/List/Util.pm
# (略) require XSLoader; XSLoader::load('List::Util', $XS_VERSION);
Scalar::Utilの上位にList::Utilがあったのか。
つまり、unless の中通るのは、
- Scalar::UtilがList::Utilをrequire
- List::UtilがXS読み込み
- XS読み込み失敗したらサブルーチンdualvar()がインポートできない
- Scalar::UtilがPurePerl(PP)を用いたバージョンのpackageをインポートしてカバー
という流れか。
言ってみれば今まで僕が見ていたPerlバージョンのlooks_like_number()は保険だったのだ。
そりゃ挙動が違うよなー。
ちょっと適当に見すぎていたよ。
ではXSインポート成功時に使われる本物のlooks_like_number()のコードはというと。
ListUtil.xs
int looks_like_number(sv) SV *sv PROTOTYPE: $ CODE: SV *tempsv; if (SvAMAGIC(sv) && (tempsv = AMG_CALLun(sv, numer))) { sv = tempsv; } else if (SvMAGICAL(sv)) { SvGETMAGIC(sv); } #if (PERL_VERSION < 8) || (PERL_VERSION == 8 && PERL_SUBVERSION <5) if (SvPOK(sv) || SvPOKp(sv)) { RETVAL = looks_like_number(sv); } else { RETVAL = SvFLAGS(sv) & (SVf_NOK|SVp_NOK|SVf_IOK|SVp_IOK); } #else RETVAL = looks_like_number(sv); #endif OUTPUT: RETVAL
あう。
RETVALが返ってくるのが分かるけど、中間がさっぱりだよ。
次はこっからもうちょっと見るかなー。
参考:
XS入門その4 typemap - CとPerlの型変換 - ケーズメモ404 Blog Not Found:perl - Scalar::Util::dualvar()