perlpragma - ユーザプラグマの書き方
perlpragma - how to write a user pragma

目次 TABLE OF CONTENTS


名前 NAME

perlpragma - ユーザプラグマの書き方 perlpragma - how to write a user pragma


説明 DESCRIPTION

プラグマとは, strictwarnings といったような, Perl の コンパイル時若しくは実行時のある状況に影響を与えるモジュールのことです. Perl 5.10 ではもう組み込みのプラグマだけに制限されません; レキシカル スコープでユーザ機能の振る舞いを偏光するユーザプラグマを作成することが できます. A pragma is a module which influences some aspect of the compile time or run time behaviour of Perl, such as strict or warnings. With Perl 5.10 you are no longer limited to the built in pragmata; you can now create user pragmata that modify the behaviour of user functions within a lexical scope.


基本的な例 A basic example

例えば, 算術演算のオーバーロードを行うクラスを作る必要があり, それを以下のように use integer; 風に提供したいとします. For example, say you need to create a class implementing overloaded mathematical operators, and would like to provide your own pragma that functions much like use integer; You'd like this code

    use MyMaths;
    
    my $l = MyMaths->new(1.2);
    my $r = MyMaths->new(3.4);
    
    print "A: ", $l + $r, "\n";
    
    use myint;
    print "B: ", $l + $r, "\n";
    
    {
        no myint;
        print "C: ", $l + $r, "\n";
    }
    
    print "D: ", $l + $r, "\n";
    
    no myint;
    print "E: ", $l + $r, "\n";

対応する出力: to give the output

    A: 4.6
    B: 4
    C: 4.6
    D: 4
    E: 4.6

つまり, use myint; の影響下にある場所では加算は整数で行われ, 一方デフォルトではそうではなく(浮動小数点でもおこなわれる), no myint; を使うことでデフォルトの振る舞いに戻すことも出来ます. i.e., where use myint; is in effect, addition operations are forced to integer, whereas by default they are not, with the default behaviour being restored via no myint;

MyMaths パッケージの最小の実装は次のようになるでしょう: The minimal implementation of the package MyMaths would be something like this:

    package MyMaths;
    use warnings;
    use strict;
    use myint();
    use overload '+' => sub {
        my ($l, $r) = @_;
	# Pass 1 to check up one call level from here
        if (myint::in_effect(1)) {
            int($$l) + int($$r);
        } else {
            $$l + $$r;
        }
    };
    
    sub new {
        my ($class, $value) = @_;
        bless \$value, $class;
    }
    
    1;

ユーザプラグマ myint を空のリスト () でロードすることで その import が呼び出されないようにしています. Note how we load the user pragma myint with an empty list () to prevent its import being called.

Perl のコンパイル時の動作は myint パッケージに対して作用します: The interaction with the Perl compilation happens inside package myint:

    package myint;
    
    use strict;
    use warnings;
    
    sub import {
        $^H{myint} = 1;
    }
    
    sub unimport {
        $^H{myint} = 0;
    }
    
    sub in_effect {
        my $level = shift // 0;
        my $hinthash = (caller($level))[10];
        return $hinthash->{myint};
    }
    
    1;

プラグマは他のモジュールと同様のモジュールとして実装されているため, use myint; は次のようになり As pragmata are implemented as modules, like any other module, use myint; becomes

    BEGIN {
        require myint;
        myint->import();
    }

no myint; は次のようになります. and no myint; is

    BEGIN {
        require myint;
        myint->unimport();
    }

従って import 及び unimport ルーチンはユーザのコードの コンパイル時 に呼び出されます. Hence the import and unimport routines are called at compile time for the user's code.

ユーザプラグマは自身の状態をマジカルハッシュ %^H に書き出すことで 保存します, なのでこの2つのルーチンではその操作を行っています. %^H に格納されている情報は optree に保存され, 実行時には caller() 関数で返されるリストのインデックス値 10 で取得できます. 例示したプラグまでは, 取得は in_effect ルーチンにカプセル化 されていて, ユーザスクリプトの中でのプラグマの値を探すために コールフレームを繰り登る回数をパラメータで受け取ります. これはユーザのスクリプトの各行が呼び出されたときに $^H{myint} の値を確定するために caller() を使っており, それによって オーバーロードされた加算演算を実装しているサブルーチンに対して 適切なセマンティクスを提供しています. User pragmata store their state by writing to the magical hash %^H, hence these two routines manipulate it. The state information in %^H is stored in the optree, and can be retrieved at runtime with caller(), at index 10 of the list of returned results. In the example pragma, retrieval is encapsulated into the routine in_effect(), which takes as parameter the number of call frames to go up to find the value of the pragma in the user's script. This uses caller() to determine the value of $^H{myint} when each line of the user's script was called, and therefore provide the correct semantics in the subroutine implementing the overloaded addition.


実装の詳細 Implementation details

optree はスレッド間で共有されています. これは optree がそれを 作った特定のスレッドよりも長生きである(つまりインタプリタの インスタンスよりも)ことを意味し, そして実際に Perl のスカラは optree に格納することはできません. 代わりにコンパクト形式が使われて います, これは整数(符号付及び符号なし), 文字列 若しくは undef のみを格納することができます - リファレンスやポインタ値は文字列化 されます. もし複数の値や複雑な構造を保存したいときには例えばpack 等でシリアライズする必要があります.%^H からのハッシュキーの 削除は記録され, undef 値を持っている存在するキーとは exists によって区別できます. The optree is shared between threads. This means there is a possibility that the optree will outlive the particular thread (and therefore the interpreter instance) that created it, so true Perl scalars cannot be stored in the optree. Instead a compact form is used, which can only store values that are integers (signed and unsigned), strings or undef - references and floating point values are stringified. If you need to store multiple values or complex structures, you should serialise them, for example with pack. The deletion of a hash key from %^H is recorded, and as ever can be distinguished from the existence of a key with value undef with exists.


和訳 TRANSALTE TO JAPANESE

 山科 氷魚 (YAMASHINA Hio) <hio@hio.jp>

原典: perl VERSION 5.9.4. 翻訳日: 2007-06-23. Origlnal distribution is perl VERSION 5.9.4. Translated at 2007-06-23.

perlpragma - ユーザプラグマの書き方
perlpragma - how to write a user pragma

索引 INDEX

perlpragma - ユーザプラグマの書き方
perlpragma - how to write a user pragma