PERLOVL(1) USER COMMANDS PERLOVL(1) NAME perlovl - Perl での多重定義 SYNOPSIS package SomeThing; %OVERLOAD = ( '+' => \&myadd, '-' => \&mysub, # etc ); ... package main; $a = new SomeThing 57; $b=5+$a; CAVEAT SCRIPTOR 演算子の多重定義は、軽くは考えられない問題です。 詳細なイン プリメンテーションも、構文も、内容も 100% Larry Wall が支持 しているものではありません。 したがって、これらは、将来のい つの時点かに変更される可能性もあります。 DESCRIPTION 多重定義関数の宣言 package Number; %OVERLOAD = ( "+" => \&add, "*=" => "muas" ); では、加法の関数 Number::add() と「クラス」Number (あるいは、 基底クラスの 1 つ) の中の乗法の代入形式 *= のメソッド muas を宣言しています。 このハッシュの value としては、&{ ... } の中で使用できるものがすべてを指定できますから、サブルーティ ン名、サブルーティンへのリファレンス、無名のサブルーティンと いったものがすべて使えます。 $a+$b を実行するときに、$a がパッケージ Number 内に bless さ れたオブジェクトへのリファレンスである場合か、$a がそのよう なマスマジカルな加法を用意しているパッケージのオブジェクトで なくても、$b が Number へのリファレンスである場合に、サブル ーティン $OVERLOAD{"+"} が呼び出されます。 これは、$a+=7 と か $a++ といった、シチュエーションでも呼ばれます。 「マジッ ク自動生成」の節を参照してください。 (「マスマジカル」とい う言葉は、多重定義されたマスマティカル演算子によって起動され るメソッドを指しています。) Perl manpages Last change: Release 5.0 Patchlevel 00 1 PERLOVL(1) USER COMMANDS PERLOVL(1) 二項演算子の呼び出し方 %OVERLOAD の value の関数は、3 つ (唯一特別な場合があって、 その時は 4 つ (「最後の楽園」の節を参照) ) の引数で呼び出さ れます。 対応する演算子が、二項演算子であれば、最初の 2 つ の引数は、その演算子の 2 つの引数です。 しかしながら、通常 のオブジェクトメソッドの呼び出し法の規則によって、最初の引数 は、常にそのパッケージのオブジェクトでなければなりませんので、 7+$a のような場合には、引数の順序の入れ替えが行なわれます。 これは、加法のメソッドのインプリメンテーションについては、お そらく問題にはならないものですが、減法のメソッドにとっては、 引数を入替えるか否かは、非常に重大な問題です。 サブルーティ ン側では、この引数の入れ替えについての情報を 3 つめの引数を 調べることで、確かめることができます。 この引数は、3 種類の 値をとります: 偽 引数の順序は、現在の演算子でのものと同じである。 真 引数は、逆になっている。 undef 現在の演算子は、($a+=7 のような) 代入形式のものである が、普通の関数が、代わりに呼ばれる。 この付加的な情 報は、何らかの最適化を行なうときに、使用することがで きる。 単項演算子の呼び出し方 単項演算子は、2 番目の引数が未定義値の二項演算子であると考え られます。 つまり、$OVERLOAD{"++"} は、$a++ が実行されると きに、($a, undef, '') という引数で呼び出されます。 多重定義可能な演算子 ハッシュ %OVERLOAD では、以下の key が認識されます: + <算術演算子> +, +=, -, -=, *, *=, /, /=, %, %=, **, **=, <<, <<=, >>, >>=, x, x=, ., .=, これらの演算子について、代入形式のものが存在しないとき には、代わりに非代入形式のものが呼ばれます。 演算子 "+", "-", "+=", "-=" に対するメソッドは、インクリメント 演算子やデクリメント演算子を自動生成するために呼ばれる ことがあります。 演算子 "-" は、単項のマイナスや "abs" のメソッドがないときに自動生成するために使われます。 Perl manpages Last change: Release 5.0 Patchlevel 00 2 PERLOVL(1) USER COMMANDS PERLOVL(1) + <比較演算子> <, <=, >, >=, ==, !=, <=>, lt, le, gt, ge, eq, ne, cmp, ある演算子が無い場合にも、対応する「スペースシップ」形 式が使えるならば、代わりに使うことができます。 配列の ソートのときには、%OVERLAOD のもとの "cmp" を使って値を 比較します。 + <ビット演算子> &, ^, |, neg, !, ~, "neg" は、単項のマイナスを表わします。 "neg" のメソッ ドが指定されていないときには、引き算のメソッドを使って、 自動生成されます。 + <インクリメントとデクリメント> ++, --, 未定義であれば、足し算と引き算のメソッドが代わりに使わ れます。 これらの演算子は、プリフィクスとしても、ポス トフィクスとしても使われます。 + <超越関数> atan2, cos, sin, exp, abs, log, sqrt, "abs" がないときには、"<" か "<=>" のメソッドを、単項の マイナスか引き算のメソッドと組み合わせて、自動生成され ます。 + ブール変換、文字列変換、数値変換 bool, "", 0+, これらの中で定義していないものがあっても、残りが一つで も定義してあれば、それを代わりに使うことができます。 "bool" は、(while のような) フロー制御演算子や、三項演 算子 "?:" で使われます。 これらの関数は、任意の Perl 値を返すことができます。 この値に対応する演算子も多重 定義されている場合には、その演算子がその時の値を使って、 再度呼び出されることになります。 + <特殊 key> nomethod, fallback, =, 「%OVERLOAD の特殊 key」の章を参照してください。 Perl manpages Last change: Release 5.0 Patchlevel 00 3 PERLOVL(1) USER COMMANDS PERLOVL(1) 見つからなかったメソッドが、いつ自動生成されるかという点につ いての説明は、fallback についての項を参照してください。 %OVERLOAD の特殊 key ここまでに説明してきたものの他に、3 つの key が Perl に認識 されます。 最後の楽園 $OVERLOAD{"nomethod"} は、4 つのパラメータを持つ関数へのリフ ァレンスです。 これが定義されていれば、多重定義の仕組みで、 何らかの演算子に対するメソッドを見つけることができなかったと きに、呼び出されます。 この関数の最初の 3 つの引数は、本来、 呼ばれるはずだったメソッドに対する引数と一致し、4 番目の引数 は、見つからなかったメソッドに対応する %OVERLOAD の key とな ります。 いくつかのメソッドが試されている場合には、最後のも のが使われます。 たとえば、1-$a であれば、 &{ $Pack::OVERLOAD{"nomethod"} }($a,1,1,"-"). とするのと同じかもしれません。 何らかの演算子が見つからず、$OVERLOAD{"nomethod"} もない場合 には、($OVERLOAD{"fallback"} が真でない限り、) die() による 例外が発生します。 fallback $OVERLOAD{"fallback"} は、特定の演算子に対するメソッドが見つ からない場合の動作を規定します。 $OVERLOAD{"fallback"} の value によって、3 つの場合があります: + 未定義 Perl は、代替のメソッドを使うことを試みます (「マジック自動生成」の節を参照してください)。 それもダメならば、$OVERLOAD{"nomethod"} を呼 び出そうとします。 これも無い場合には、例外 が発生することになります。 + 「真」 未定義の場合と同じですが、例外を発生させませ ん。 この場合、黙って、もし %OVERLOAD がな かったときに、行なってであろう動作に戻される ことになります。 + 定義済みだが「偽」 マジック自動生成は行ないません。 Perl は、 まず $OVERLOAD{"nomethod"} の実行を試みて、 これがなければ、例外を発生させます。 Perl manpages Last change: Release 5.0 Patchlevel 00 4 PERLOVL(1) USER COMMANDS PERLOVL(1) コピーコンストラクタ $OVERLOAD{"="} は、3 引数の関数へのリファレンスです。 すな わち、見かけ上は普通の %OVERLOAD の value と同じです。 この サブルーティンの特殊な点は、(他の多くのメソッドが期待されて いるように) bless された、パッケージへのリファレンスを返す必 要がありませんが、被参照した引数の新しいコピーをかえします (ただし、BUG の章をみてください)。 この演算は、 $a=$b; $a++; のような、他のリファレンスとオブジェクトを共有するリファレン スに対して、ミューテーターを使うときに呼び出されます。 これ を、$a を変更し、$b を変更しないようにするために、$$a の新し いコピーを作り、このオブジェクトへのリファレンスが $a に代入 されます。 この操作は、$a++ の実行中に (すなわち、その前に $$a が $$b に一致します)、++ が $OPERATOR{'++'} か $OPERATOR{'+='} で表現されているときにだけ行なわれます。 こ の演算子が、"+" を使って、 $a=$b; $a=$a+1; のように表現されていれば、$$a も $$b も、左辺値として現われ ることはありません。 コピーコンストラクタが、いくつかのミューテーターの実行中に必 要となって、$OPERATOR{'='} が見つからないときには、そのパッ ケージのオブジェクトが単なるスカラであれば、文字列コピーとし て自動生成されます。 マジック自動生成 演算子に対するメソッドが見つからず、$OVERLOAD{"fallback"} が 「真」か「未定義」であれば、Perl は、定義されている演算子を もとに、見つからなかった演算子の代わりのメソッドを自動生成し ようと試みます。 以下の演算子に対して、自動生成代替メソッド が行なえます: 算術演算子の代入形式 $OVERLOAD{"+="} が定義されていないとき、 $a=+$b は、$OVERLOAD{"+"} メソッドを使うこと ができます。 変換演算子 文字列、数値、ブール値変換は、すべてが定義さ れてはいないとき、互いに別のもので計算されま す。 インクリメントとデクリメント 演算 ++$a は、$a+=1 か $a+1 で、演算 $a-- は、 $a-=1 か $a-1 で表現することができます。 Perl manpages Last change: Release 5.0 Patchlevel 00 5 PERLOVL(1) USER COMMANDS PERLOVL(1) abs($a) abs($a) は、$a<0 と -$a (または 0-$a) で表現 できます。 単項のマイナス 単項のマイナスは、引き算を使って表現できます。 連結 連結は、文字列変換を使って表現できます。 比較演算子 比較演算は、それぞれに対応するスペースシップ 演算 (<=> か cmp) を用いて表現することができ ます: <, >, <=, >=, ==, != は、<=> を使う lt, gt, le, ge, eq, ne は、cmp を使う コピー演算 コピー演算は被参照した値が、リファレンスでは ないスカラであれば、その値への代入という形で 表現できます。 WARNING 比較演算子に対する制限は、たとえば、"cmp" が bless されたリ ファレンスを返さなければならないとしても、自動生成された関数 "lt" は、"cmp" の結果の数値に基づく標準の論理値だけを作り出 します。 特に、この場合には、(ときには別の変換で表わされた) 数値変換が使えないといけません。 同様に、.= 演算子や x= 演算子も、文字列変換による代替が起こ れば、マスマジカルな性質がなくなります。 マスマジカルなオブジェクトを chop() すると、まず文字列になり、 マスマジカルな部分はなくなります。 同じことは、他の演算でも 起こります。 IMPLEMENTATION すべての演算のためのメソッドのテーブルは、該当パッケージのシ ンボルテーブルに対するマジックとしてキャッシュされます。 こ れは、bless を行なうときにのみ、%OVERLOAD と @ISA の変更を再 チェックします。 つまり、動的に変更したいならば、テーブルを 更新するために、意味の無い bless を行なう必要があります。 (すべての SV 風のものは、マジックキューを持っており、マジッ クがキューのエントリになっています。 これによって、1 つの変 数が、同時に複数のマジックの形式に関ることができるのです。 たとえば、環境変数は普段、%ENV マジックと「汚染」マジックの 2 つの形式を一度に持っています。) オブジェクトが %OVERLOAD を持つパッケージに属するならば、そ のオブジェクトには、特別なフラグが用意されます。 つまり、多 重定義されていない算術演算を行なうときの、スピードに対する影 響は、このフラグのチェックのみです。 Perl manpages Last change: Release 5.0 Patchlevel 00 6 PERLOVL(1) USER COMMANDS PERLOVL(1) 実際、%OVERLOAD がアクセスされない間は、多重定義可能な演算に 対するオーバヘッドはほとんど無く、ほとんどのプログラムで、認 識できるようなパフォーマスの低下はないはずです。 %OVERLOAD がアクセスされ、その時の演算が多重定義可能なものであったとき にも、対象の引数が %OVERLOAD を持ったパッケージに属していな い場合には、オーバヘッドの最小限にする最大限の努力が為されま した。 疑わしいときには、%OVERLOAD がある場合と無い場合で、 スピードのテストをしてください。 これまでのところ、Perl が 最適化を指定してコンパイル場合には、顕著なスピードの低下の報 告はあがっていません。 %OVERLOAD が存在しないときには、データの大きさには影響しませ ん。 $a=$b のようなコピーは、表層的なものです。 しかし、$b++ の ように、$b (または、$a) が参照するオブジェクトへの代入を意味 する演算の前に、1 層深度のコピーが行なわれます。 この動作は、 自分でコピーコンストラクタを定義することによって変更すること ができます (「コピーコンストラクタ」の項を参照してください)。 明示的にサポートされていないメソッドに対する引数は、定数であ ることが期待されます (が、強制はされません)。 AUTHOR Ilya Zakharevich <ilya@math.mps.ohio-state.edu>. DIAGNOSTICS Perl を -Do スイッチか同等のものを使って起動すると、多重定義 が、診断メッセージを誘発します。 BUGS 多重定義に使用されるため、Perl では、連想配列 %OVERLOAD は、 パッケージごとに特別な意味を持つことになります。 コピーコンストラクタは、配列へのリファレンスを伴う多重定義演 算をより単純にするように、特別に設計されていますが、動作する ときには、現在はこの事には役に立ちません。 (Perl 内部の視点 からすると) サブルーティンは、スカラを返すのと同じようには、 配列を返すことができないからです。 コピーコンストラクタのた めのインタフェースが変更されることを期待します。 出荷時、%OVERLOAD は @ISA によって継承されていません。 これ に対するパッチが、作者 (author) から得られます。 このドキュメントは混乱しています。 Perl manpages Last change: Release 5.0 Patchlevel 00 7