- 名前
- 概要
- 説明
- SPECIAL SYMBOLS FOR
use overload
- マジック自動生成
- オーバーロードされた演算の最小セット
- オーバーロードが失われるとき
- 実行時オーバーロード
- パブリック関数
- 定数のオーバーロード
- 実装
- 比喩の衝突
- レシピ集
- 作者
- DIAGNOSTICS
- バグ
名前¶
overload - Package for overloading Perl operations
overload - Perl の演算子のオーバーロードを行うパッケージ
概要¶
package SomeThing;
use overload
'+' => \&myadd,
'-' => \&mysub;
# etc
...
package main;
$a = new SomeThing 57;
$b=5+$a;
...
if (overload::Overloaded $b) {...}
...
$strval = overload::StrVal $b;
説明¶
オーバーロード関数の宣言¶
The compilation directive
コンパイル指示子
package Number;
use overload
"+" => \&add,
"*=" => "muas";
declares function Number::add() for addition, and method muas() in the "class" Number
(or one of its base classes) for the assignment form *=
of multiplication.
では、加法の関数 Number::add() と「クラス」Number
(あるいは、 その基底クラスの 1 つ) の中の乗法の代入形式 *=
のメソッド muas() を 宣言しています。
Arguments of this directive come in (key, value) pairs. Legal values are values legal inside a &{ ... }
call, so the name of a subroutine, a reference to a subroutine, or an anonymous subroutine will all work. Note that values specified as strings are interpreted as methods, not subroutines. Legal keys are listed below.
この指示子の引数は (key, value) のペアです。 この value としては、&{ ... }
の中で使用できるものが すべてを指定できますから、サブルーチン名、 サブルーチンへのリファレンス、無名のサブルーチンといったものが すべて使えます。 文字列として指定された値はサブルーチンではなく、 メソッドとして解釈されることに注意してください。 key として有効な値は以下に述べます。
The subroutine add
will be called to execute $a+$b
if $a is a reference to an object blessed into the package Number
, or if $a is not an object from a package with defined mathemagic addition, but $b is a reference to a Number
. It can also be called in other situations, like $a+=7
, or $a++
. See "MAGIC AUTOGENERATION". (Mathemagical methods refer to methods triggered by an overloaded mathematical operator.)
$a+$b
を実行するときに、$a がパッケージ Number
内に bless されたオブジェクトへのリファレンスである場合か、 $a がそのようなマスマジカルな加法を用意しているパッケージの オブジェクトでなくても、$b が Number へのリファレンスである場合に、 サブルーチン add
が呼び出されます。 これは、$a+=7
とか $a++
といった、シチュエーションでも呼ばれます。 "MAGIC AUTOGENERATION" の節を参照してください。 (「マスマジカル」という言葉は、オーバーロードされた 算術演算子によって起動されるメソッドを指しています。)
Since overloading respects inheritance via the @ISA hierarchy, the above declaration would also trigger overloading of +
and *=
in all the packages which inherit from Number
.
オーバーロードは @ISA 階層による継承を遵守するので、上述の宣言は Number
から継承される全てのパッケージの +
と *=
のオーバーロードも 引き起こすことになります。
二項演算子の呼び出し規約¶
The functions specified in the use overload ...
directive are called with three (in one particular case with four, see "Last Resort") arguments. If the corresponding operation is binary, then the first two arguments are the two arguments of the operation. However, due to general object calling conventions, the first argument should always be an object in the package, so in the situation of 7+$a
, the order of the arguments is interchanged. It probably does not matter when implementing the addition method, but whether the arguments are reversed is vital to the subtraction method. The method can query this information by examining the third argument, which can take three different values:
use overload ...
指示子で指定される関数は、 3 つ (唯一特別な場合があって、 その時は 4 つ ("Last Resort"の節を参照) ) の引数で呼び出されます。 対応する演算子が、二項演算子であれば、最初の 2 つの引数は、 その演算子の 2 つの引数です。 しかしながら、通常のオブジェクトメソッドの呼び出し規約によって、 最初の引数は、常にそのパッケージのオブジェクトでなければなりませんので、 7+$a
のような場合には、引数の順序の入れ替えが行なわれます。 これは、加法のメソッドを実装する時には、 おそらく問題にはならないものですが、減法のメソッドにとっては、 引数を入替えるか否かは、非常に重大な問題です。 メソッド側では、この引数の入れ替えについての情報を 3 つめの引数を 調べることで、確かめることができます。 この引数は、3 種類の値をとります:
- FALSE
-
(偽)
the order of arguments is as in the current operation.
引数の順序は、現在の演算子でのものと同じです。
- TRUE
-
(真)
the arguments are reversed.
引数は、逆になっています。
undef
-
the current operation is an assignment variant (as in
$a+=7
), but the usual function is called instead. This additional information can be used to generate some optimizations. Compare "Calling Conventions for Mutators".現在の演算子は、(
$a+=7
のような) 代入形式のものですが、 代わりに普通の関数が呼ばれます。 この付加的な情報は、何らかの最適化を行なうときに 使用できます。 "Calling Conventions for Mutators" と比較してください。
単項演算子の呼び出し規約¶
Unary operation are considered binary operations with the second argument being undef
. Thus the functions that overloads {"++"}
is called with arguments ($a,undef,'')
when $a++ is executed.
単項演算子は、2 番目の引数が undef
の二項演算子であると 考えられます。 つまり、{"++"}
をオーバーロードする関数は、 $a++ が実行されるときに、($a, undef, '')
という引数で呼び出されます。
ミューテータの呼び出し規約¶
Two types of mutators have different calling conventions:
2 種類のミューテータは異なった呼び出し規約を持ちます:
++
and--
-
(
++
と--
)The routines which implement these operators are expected to actually mutate their arguments. So, assuming that $obj is a reference to a number,
これらの演算子を実装するルーチンは、実際はこれらの引数を 変更(mutate) することを想定しています。 それで、$obj が数値へのリファレンスと仮定すると、
sub incr { my $n = $ {$_[0]}; ++$n; $_[0] = bless \$n}
is an appropriate implementation of overloaded
++
. Note thatはオーバーロードした
++
の適切な実装です。以下のものはsub incr { ++$ {$_[0]} ; shift }
is OK if used with preincrement and with postincrement. (In the case of postincrement a copying will be performed, see "Copy Constructor".)
事前インクリメントと事後インクリメントの場合は OK であることに 注意してください。 事後インクリメントの場合、コピーが実行されます。 "Copy Constructor" を参照してください。)
x=
and other assignment versions-
(
x=
とその他の代入演算子)There is nothing special about these methods. They may change the value of their arguments, and may leave it as is. The result is going to be assigned to the value in the left-hand-side if different from this value.
これらのメソッドについて何も特別なものはありません。 引数の値を変更するかもしれませんし、そのままかもしれません。 結果は、もしこの値と違うなら左側の値に代入されることになります。
This allows for the same method to be used as overloaded
+=
and+
. Note that this is allowed, but not recommended, since by the semantic of "Fallback" Perl will call the method for+
anyway, if+=
is not overloaded.これは、オーバーロードした
+=
と+
として同じメソッドを使うことを 許します。 これは 許されます が、推奨されません; なぜなら "Fallback" の 意味論によって Perl はもし+=
がオーバーロードされていなければ とにかく+
を呼び出すからです。
Warning. Due to the presence of assignment versions of operations, routines which may be called in assignment context may create self-referential structures. Currently Perl will not free self-referential structures until cycles are explicitly
broken. You may get problems when traversing your structures too.
警告: 演算の代入版の存在によって、代入コンテキストで呼び出される ルーチンは自己参照構造を作るかもしれません。 現在のところ、Perl は循環が 明示的に
破壊されるまで自己参照構造を 解放しません。 構造をたどっていくときにも問題になるかもしれません。
Say,
以下のようにすると、
use overload '+' => sub { bless [ \$_[0], \$_[1] ] };
is asking for trouble, since for code $obj += $foo
the subroutine is called as $obj = add($obj, $foo, undef)
, or $obj = [\$obj, \$foo]
. If using such a subroutine is an important optimization, one can overload +=
explicitly by a non-"optimized" version, or switch to non-optimized version if not defined $_[2]
(see "Calling Conventions for Binary Operations").
は自ら災いを招くことになります; なぜなら $obj += $foo
というコードでは サブルーチンは $obj = add($obj, $foo, undef)
あるいは $obj = [\$obj, \$foo]
として呼び出されるからです。 もしこのようなサブルーチンを使うことが重要な最適化なら、 非「最適化」版で明示的に +=
をオーバーロードするか、 もし not defined $_[2]
なら非最適化版に切り替えることができます ("Calling Conventions for Binary Operations" を参照してください)。
Even if no explicit assignment-variants of operators are present in the script, they may be generated by the optimizer. Say, ",$obj,"
or ',' . $obj . ','
may be both optimized to
たとえスクリプトで 明示的に 代入系の演算子を使っていなくても、 オプティマイザによって生成されるかもしれません。 例えば、",$obj,"
や ',' . $obj . ','
は両方とも以下のように 最適化されるかもしれません
my $tmp = ',' . $obj; $tmp .= ',';
オーバーロードできる操作¶
The following symbols can be specified in use overload
directive:
以下のシンボルが use overload
指示子で指定できます:
Arithmetic operations
(算術演算子)
"+", "+=", "-", "-=", "*", "*=", "/", "/=", "%", "%=", "**", "**=", "<<", "<<=", ">>", ">>=", "x", "x=", ".", ".=",
For these operations a substituted non-assignment variant can be called if the assignment variant is not available. Methods for operations
+
,-
,+=
, and-=
can be called to automatically generate increment and decrement methods. The operation-
can be used to autogenerate missing methods for unary minus orabs
.これらの演算子について、代入形式のものが存在しないときには、代わりに 非代入形式のものが呼ばれます。 演算子
+
,-
,+=
,-=
に対するメソッドは、 インクリメント演算子やデクリメント演算子を自動生成するために 呼ばれることがあります。 演算子-
は、単項のマイナスやabs
のメソッドがないときに 自動生成するために使われます。See "MAGIC AUTOGENERATION", "Calling Conventions for Mutators" and "Calling Conventions for Binary Operations") for details of these substitutions.
これらの置換に関する詳細については "MAGIC AUTOGENERATION", "Calling Conventions for Mutators", "Calling Conventions for Binary Operations" を参照して下さい。
Comparison operations
(比較演算子)
"<", "<=", ">", ">=", "==", "!=", "<=>", "lt", "le", "gt", "ge", "eq", "ne", "cmp",
If the corresponding "spaceship" variant is available, it can be used to substitute for the missing operation. During
sort
ing arrays,cmp
is used to compare values subject touse overload
.ある演算子が無い場合にも、対応する「スペースシップ」形式が使えるならば、 代わりに使うことができます。 配列のソートのときには、
use overload
のもとのcmp
を使って値を 比較します。Bit operations
(ビット演算子)
"&", "&=", "^", "^=", "|", "|=", "neg", "!", "~",
neg
stands for unary minus. If the method forneg
is not specified, it can be autogenerated using the method for subtraction. If the method for!
is not specified, it can be autogenerated using the methods forbool
, or""
, or0+
.neg
は、単項のマイナスを表わします。neg
のメソッドが指定されていないときには、 引き算のメソッドを使って、自動生成されます。!
のメソッドが指定されていないときには、bool
,\"\"
,0+
のいずれかのメソッドを使って 自動生成されます。The same remarks in "Arithmetic operations" about assignment-variants and autogeneration apply for bit operations
"&"
,"^"
, and"|"
as well."Arithmetic operations" での様々な代入と自動生成に関する意見は ビット操作
"&"
,"^"
,"|"
にも適用されます。Increment and decrement
(インクリメントとデクリメント)
"++", "--",
If undefined, addition and subtraction methods can be used instead. These operations are called both in prefix and postfix form.
未定義であれば、足し算と引き算のメソッドが代わりに使われます。 これらの演算子は、前置としても後置としても使われます。
Transcendental functions
(超越関数)
"atan2", "cos", "sin", "exp", "abs", "log", "sqrt", "int"
If
abs
is unavailable, it can be autogenerated using methods for "<" or "<=>" combined with either unary minus or subtraction.abs
がないときには、"<" か "<=<>" のメソッドを、 単項のマイナスか引き算のメソッドと組み合わせて、 自動生成されます。Note that traditionally the Perl function int rounds to 0, thus for floating-point-like types one should follow the same semantic. If
int
is unavailable, it can be autogenerated using the overloading of0+
.伝統的に Perl 関数 int は 0 に丸めるので、浮動小数点風の型は同じ 意味論に従うべきです。 もし
int
が利用不可能なら、0+
のオーバーロードを使って 自動生成されます。Boolean, string and numeric conversion
(ブール変換、文字列変換、数値変換)
'bool', '""', '0+',
If one or two of these operations are not overloaded, the remaining ones can be used instead.
bool
is used in the flow control operators (likewhile
) and for the ternary?:
operation. These functions can return any arbitrary Perl value. If the corresponding operation for this value is overloaded too, that operation will be called again with this value.これらの中でオーバーロードしていないものがあっても、残りが一つで も定義してあれば、それを代わりに使うことができます。
bool
は、(while
のような) フロー制御演算子や、 三項演算子?:
で使われます。 これらの関数は、任意の Perl 値を返すことができます。 この値に対応する演算子もオーバーロードされている場合には、 その演算子がその時の値を使って、再度呼び出されることになります。As a special case if the overload returns the object itself then it will be used directly. An overloaded conversion returning the object is probably a bug, because you're likely to get something that looks like
YourPackage=HASH(0x8172b34)
.特別な場合として、オーバーロードがオブジェクト自身を返した場合、 これが直接使われます。 オブジェクトを返すオーバーロードされた変換はおそらくバグです; なぜなら おそらく
YourPackage=HASH(0x8172b34)
のようなものを受け取るからです。Iteration
(反復子)
"<>"
If not overloaded, the argument will be converted to a filehandle or glob (which may require a stringification). The same overloading happens both for the read-filehandle syntax
<$var>
and globbing syntax<${var}>
.オーバーロードされないと、引数はファイルハンドルかグロブに変換されます (文字列化が必要かもしれません)。 同じオーバーロードは ファイルハンドル読み込み 構文
<$var>
と グロブ 構文<${var}>
の両方でも起こります。BUGS Even in list context, the iterator is currently called only once and with scalar context.
バグ たとえリストコンテキストでも、現在のところ反復子は スカラコンテキストで 1 度だけしか呼び出されない。
Dereferencing
(デリファレンス)
'${}', '@{}', '%{}', '&{}', '*{}'.
If not overloaded, the argument will be dereferenced as is, thus should be of correct type. These functions should return a reference of correct type, or another object with overloaded dereferencing.
オーバーロードされないと、引数は そのままで デリファレンスされ、 正しい型になるべきです。 これらの関数は正しい型のリファレンスか、オーバーロードされた デリファレンスと共に他のオブジェクトが返されるべきです。
As a special case if the overload returns the object itself then it will be used directly (provided it is the correct type).
特別な場合として、オーバーロードがオブジェクト自身を返した場合、 (正しい型なら)これが直接使われます。
The dereference operators must be specified explicitly they will not be passed to "nomethod".
デリファレンス演算子は "nomethod" を渡されないように明示的に 指定されなければなりません。
Special
(特殊 key)
"nomethod", "fallback", "=", "~~",
"SPECIAL SYMBOLS FOR
use overload
" を参照してください。
See "Fallback" for an explanation of when a missing method can be autogenerated.
存在しないメソッドの自動生成についての説明は "Fallback" を参照して下さい。
A computer-readable form of the above table is available in the hash %overload::ops, with values being space-separated lists of names:
上述のテーブルのコンピュータ可読形式は、ハッシュ %overload::ops で 利用可能です; 値は空白で区切られた名前のリストです:
with_assign => '+ - * / % ** << >> x .',
assign => '+= -= *= /= %= **= <<= >>= x= .=',
num_comparison => '< <= > >= == !=',
'3way_comparison'=> '<=> cmp',
str_comparison => 'lt le gt ge eq ne',
binary => '& &= | |= ^ ^=',
unary => 'neg ! ~',
mutators => '++ --',
func => 'atan2 cos sin exp abs log sqrt',
conversion => 'bool "" 0+',
iterators => '<>',
dereferencing => '${} @{} %{} &{} *{}',
special => 'nomethod fallback ='
継承とオーバーロード¶
Inheritance interacts with overloading in two ways.
継承はオーバーロードに二つの方法で関わります。
- Strings as values of
use overload
directive -
(
use overload
指示子の値としての文字列)If
value
inもし以下での
value
がuse overload key => value;
is a string, it is interpreted as a method name.
文字列の場合、メソッド名として解釈されます。
- Overloading of an operation is inherited by derived classes
-
(操作のオーバーロードは派生クラスによって継承される)
Any class derived from an overloaded class is also overloaded. The set of overloaded methods is the union of overloaded methods of all the ancestors. If some method is overloaded in several ancestor, then which description will be used is decided by the usual inheritance rules:
オーバーロードされたクラスから派生したクラスもオーバーロードされます。 オーバーロードされたメソッドの集合は全ての祖先のオーバーロードされた メソッドの結合です。 もしあるメソッドが複数の祖先によってオーバーロードされているなら、 どれが使われるかは通常の継承ルールによって決定されます:
If
A
inherits fromB
andC
(in this order),B
overloads+
with\&D::plus_sub
, andC
overloads+
by"plus_meth"
, then the subroutineD::plus_sub
will be called to implement operation+
for an object in packageA
.もし
A
がB
をC
を (この順序で) 継承していて、B
が+
を\&D::plus_sub
でオーバーロードし、C
が+
を"plus_meth"
で オーバーロードしている場合、パッケージA
でオブジェクトのために 演算+
を実装するために、サブルーチンD::plus_sub
が呼び出されます。
Note that since the value of the fallback
key is not a subroutine, its inheritance is not governed by the above rules. In the current implementation, the value of fallback
in the first overloaded ancestor is used, but this is accidental and subject to change.
fallback
キーの値はサブルーチンではないので、この継承は上述のルールには 従いません。 現在の実装では、最初にオーバーロードした祖先の fallback
の値が 使われますが、これは偶然で、変更される予定です。
SPECIAL SYMBOLS FOR use overload
¶
(use overload
の特殊シンボル)
Three keys are recognized by Perl that are not covered by the above description.
ここまでに説明してきたものの他に、3 つの key が Perl に認識されます。
最後の手段¶
"nomethod"
should be followed by a reference to a function of four parameters. If defined, it is called when the overloading mechanism cannot find a method for some operation. The first three arguments of this function coincide with the arguments for the corresponding method if it were found, the fourth argument is the symbol corresponding to the missing method. If several methods are tried, the last one is used. Say, 1-$a
can be equivalent to
"nomethod"
は、4 つのパラメータを持つ関数へのリファレンスが引き続きます。 これが定義されていれば、オーバーロードの仕組みで、 何らかの演算子に対するメソッドを見つけることができなかったときに、 呼び出されます。 この関数の最初の 3 つの引数は、本来、 呼ばれるはずだったメソッドに対する引数と一致し、4 番目の引数は、 見つからなかったメソッドに対応するシンボルとなります。 いくつかのメソッドが試されている場合には、最後のものが使われます。 たとえば、1-$a
であれば、 "nomethod" => "nomethodMethod"
の組が use overload
指示子で 指定されていれば:
&nomethodMethod($a,1,1,"-")
if the pair "nomethod" => "nomethodMethod"
was specified in the use overload
directive.
と同様です。
The "nomethod"
mechanism is not used for the dereference operators ( ${} @{} %{} &{} *{} ).
"nomethod"
の機構は デリファレンス演算子 ( ${} @{} %{} &{} *{} ) では 使用されません。
If some operation cannot be resolved, and there is no function assigned to "nomethod"
, then an exception will be raised via die()-- unless "fallback"
was specified as a key in use overload
directive.
何らかの演算子が見つからず、"nomethod"
に結び付けられた関数もない 場合には、("fallback"
が use overload
指示子のキーとして 指定されていない限り) die() による例外が発生します。
フォールバック¶
The key "fallback"
governs what to do if a method for a particular operation is not found. Three different cases are possible depending on the value of "fallback"
:
"fallback"
は、特定の演算子に対するメソッドが見つからない場合の 動作を規定します。 "fallback"
の value によって、3 つの場合があります:
undef
Perl tries to use a substituted method (see "MAGIC AUTOGENERATION"). If this fails, it then tries to calls
"nomethod"
value; if missing, an exception will be raised.Perl は、代替のメソッドを使うことを試みます ("MAGIC AUTOGENERATION" の節を参照してください)。 それもダメならば、
"nomethod"
を呼び出そうとします。 これも無い場合には、例外が発生することになります。TRUE
(真)
The same as for the
undef
value, but no exception is raised. Instead, it silently reverts to what it would have done were there nouse overload
present.undef
の場合と同じですが、例外を発生させません。 この場合、黙って、もしuse overload
がなかったときに、 行なってであろう動作に戻されることになります。defined, but FALSE
(定義済みだが「偽」)
No autogeneration is tried. Perl tries to call
"nomethod"
value, and if this is missing, raises an exception.マジック自動生成は行ないません。 Perl は、まず
"nomethod"
の実行を試みて、 これがなければ、例外を発生させます。
Note. "fallback"
inheritance via @ISA is not carved in stone yet, see "Inheritance and overloading".
注意: @ISA 経由の "fallback"
継承はまだ行われません。 "Inheritance and overloading" を参照して下さい。
スマートマッチング¶
The key "~~"
allows you to override the smart matching used by the switch construct. See feature.
キー "~~"
は switch 構文で使われるスマートマッチングを オーバーロードすることを可能にします。 feature を参照してください。
コピーコンストラクタ¶
The value for "="
is a reference to a function with three arguments, i.e., it looks like the other values in use overload
. However, it does not overload the Perl assignment operator. This would go against Camel hair.
"="
の値は、3 引数の関数へのリファレンスです。 つまり、use overload
の他の値と似ているように見えます。 しかし、これは Perl の代入演算子をオーバーロードしません。 これは「ラクダの毛(Camel hair)」に対抗しています。
This operation is called in the situations when a mutator is applied to a reference that shares its object with some other reference, such as
この演算は、以下のような、他のリファレンスとオブジェクトを共有する リファレンスに対して、ミューテータを使うときに呼び出されます。
$a=$b;
++$a;
To make this change $a and not change $b, a copy of $$a
is made, and $a is assigned a reference to this new object. This operation is done during execution of the ++$a
, and not during the assignment, (so before the increment $$a
coincides with $$b
). This is only done if ++
is expressed via a method for '++'
or '+='
(or nomethod
). Note that if this operation is expressed via '+'
a nonmutator, i.e., as in
これを、$a を変更し、$b を変更しないようにするために、$$a
のコピーを作り、 この新しいオブジェクトへのリファレンスが $a に代入されます。 この操作は、++$a
の実行中に (すなわち、その前に $$a
が $$b
に一致します)、行われます。 これは++
が '++'
か '+='
(か nomethod
) のメソッドを通じて 表現されているときにだけ行なわれます。 この演算子が、非ミューテータ "+"
を使って記述されている場合、
$a=$b;
$a=$a+1;
then $a
does not reference a new copy of $$a
, since $$a does not appear as lvalue when the above code is executed.
$a
は $$a
の新しいコピーのリファレンスではありません。 上記のコードが実行されたときに $$a は左辺値としては現れていないからです。
If the copy constructor is required during the execution of some mutator, but a method for '='
was not specified, it can be autogenerated as a string copy if the object is a plain scalar.
コピーコンストラクタが、いくつかのミューテータの実行中に必要となって、 '='
が指定されていないときには、そのオブジェクトが 単なるスカラであれば、文字列コピーとして自動生成されます。
- Example
-
(例)
The actually executed code for
以下の記述で
$a=$b; Something else which does not modify $a or $b.... ++$a;
may be
実際に実行されるコードは以下のようになります
$a=$b; Something else which does not modify $a or $b.... $a = $a->clone(undef,""); $a->incr(undef,"");
if $b was mathemagical, and
'++'
was overloaded with\&incr
,'='
was overloaded with\&clone
.(もし $b がマスマジカルで、
'++'
が\&incr
でオーバーロードされていて、'='
が\&clone
でオーバーロードされていれば。)
Same behaviour is triggered by $b = $a++
, which is consider a synonym for $b = $a; ++$a
.
同じ振る舞いは $b = $a++
で引き起こされます; これは $b = $a; ++$a
と同義として扱われます。
マジック自動生成¶
If a method for an operation is not found, and the value for "fallback"
is TRUE or undefined, Perl tries to autogenerate a substitute method for the missing operation based on the defined operations. Autogenerated method substitutions are possible for the following operations:
演算子に対するメソッドが見つからず、"fallback"
が 「真」か「未定義」であれば、Perl は、定義されている演算子を もとに、見つからなかった演算子の代わりのメソッドを自動生成しようと試みます。 以下の演算子に対して、自動生成代替メソッドが行なえます:
- Assignment forms of arithmetic operations
-
(算術演算子の代入形式)
$a+=$b
can use the method for"+"
if the method for"+="
is not defined."+="
メソッドが定義されていないとき、$a+=$b
は、"+"
メソッドを使うことができます。 - Conversion operations
-
(変換演算子)
String, numeric, and boolean conversion are calculated in terms of one another if not all of them are defined.
文字列、数値、ブール値変換は、すべてが定義されてはいないとき、 互いに別のもので計算されます。
- Increment and decrement
-
(インクリメントとデクリメント)
The
++$a
operation can be expressed in terms of$a+=1
or$a+1
, and$a--
in terms of$a-=1
and$a-1
.演算
++$a
は、$a+=1
か$a+1
で、演算$a--
は、$a-=1
か$a-1
で表現することができます。 abs($a)
-
can be expressed in terms of
$a<0
and-$a
(or0-$a
).abs($a) は、
$a<0
と-$a
(または0-$a
) で表現できます。 - Unary minus
-
(単項のマイナス)
can be expressed in terms of subtraction.
単項のマイナスは、引き算を使って表現できます。
- Negation
-
(否定)
!
andnot
can be expressed in terms of boolean conversion, or string or numerical conversion.!
とnot
はブール値変換、文字列変換、数値変換を使って 表現できます。 - Concatenation
-
(連結)
can be expressed in terms of string conversion.
連結は、文字列変換を使って表現できます。
- Comparison operations
-
(比較演算子)
can be expressed in terms of its "spaceship" counterpart: either
<=>
orcmp
:比較演算は、それぞれに対応する「スペースシップ」演算 (
<=<>
かcmp
) を用いて表現することができます:<, >, <=, >=, ==, != in terms of <=> lt, gt, le, ge, eq, ne in terms of cmp
- Iterator
-
(反復子)
<> in terms of builtin operations
- Dereferencing
-
(デリファレンス)
${} @{} %{} &{} *{} in terms of builtin operations
- Copy operator
-
(コピー演算子)
can be expressed in terms of an assignment to the dereferenced value, if this value is a scalar and not a reference.
コピー演算は被参照した値が、リファレンスではないスカラであれば、 その値への代入という形で表現できます。
オーバーロードされた演算の最小セット¶
Since some operations can be automatically generated from others, there is a minimal set of operations that need to be overloaded in order to have the complete set of overloaded operations at one's disposal. Of course, the autogenerated operations may not do exactly what the user expects. See "MAGIC AUTOGENERATION" above. The minimal set is:
演算の一部は他の演算から自動的に生成できるので、オーバーロードされた操作の 完全セットを作るためにオーバーロードする必要がある、演算の 最小セットというものが存在します。 もちろん、自動生成された演算はユーザーが想定したものと正確に 同じではないかもしれません。 上述の "MAGIC AUTOGENERATION" を参照してください。 最小セットは:
+ - * / % ** << >> x
<=> cmp
& | ^ ~
atan2 cos sin exp log sqrt int
Additionally, you need to define at least one of string, boolean or numeric conversions because any one can be used to emulate the others. The string conversion can also be used to emulate concatenation.
さらに、文字列、真偽値、数値変換のうち少なくとも 1 つを定義する必要が あります; なぜならどれでも他のものをエミュレートできるからです。 文字列変換は連結をエミュレートするためにも使われます。
オーバーロードが失われるとき¶
The restriction for the comparison operation is that even if, for example, `cmp
' should return a blessed reference, the autogenerated `lt
' function will produce only a standard logical value based on the numerical value of the result of `cmp
'. In particular, a working numeric conversion is needed in this case (possibly expressed in terms of other conversions).
比較演算子に対する制限は、たとえば、`cmp
' が bless された リファレンスを返さなければならないとしても、自動生成された関数 `lt
' は、`cmp
' の結果の数値に基づく標準の論理値だけを 作り出します。 特に、この場合には、(ときには別の変換で表わされた) 数値変換が使えないといけません。
Similarly, .=
and x=
operators lose their mathemagical properties if the string conversion substitution is applied.
同様に、.=
演算子や x=
演算子も、文字列変換による代替が起これば、 マスマジカルな性質がなくなります。
When you chop() a mathemagical object it is promoted to a string and its mathemagical properties are lost. The same can happen with other operations as well.
マスマジカルなオブジェクトを chop() すると、文字列になり、 マスマジカルな性質はなくなります。 同じことは、他の演算でも起こります。
実行時オーバーロード¶
Since all use
directives are executed at compile-time, the only way to change overloading during run-time is to
全ての use
指示子はコンパイル時に実行されるので、実行時にオーバーロードを 変更する唯一の方法は以下のものです
eval 'use overload "+" => \&addmethod';
You can also use
また、以下のようにもできます
eval 'no overload "+", "--", "<="';
though the use of these constructs during run-time is questionable.
しかし実行時にこのような構文を使うのは問題が多いです。
パブリック関数¶
Package overload.pm
provides the following public functions:
パッケージ overload.pm
は以下のパブリック関数を提供します:
- overload::StrVal(arg)
-
Gives string value of
arg
as in absence of stringify overloading. If you are using this to get the address of a reference (useful for checking if two references point to the same thing) then you may be better off usingScalar::Util::refaddr()
, which is faster.文字列化のオーバーロードがないものとしたときの
arg
の文字列値を 与えます。 もしリファレンスのアドレスを得るためにこれを使っている (2 つのリファレンスが同じものを指しているかをチェックするのに便利です)なら、 より速いScalar::Util::refaddr()
を使った方が良いでしょう。 - overload::Overloaded(arg)
-
Returns true if
arg
is subject to overloading of some operations.arg
が何らかの操作のオーバーロードの影響下にあるなら真を返します。 - overload::Method(obj,op)
-
Returns
undef
or a reference to the method that implementsop
.op
を実装しているメソッドへのリファレンス、あるいはundef
を 返します。
定数のオーバーロード¶
For some applications, the Perl parser mangles constants too much. It is possible to hook into this process via overload::constant()
and overload::remove_constant()
functions.
アプリケーションによっては Perl パーザが定数をいじりすぎる場合があります。 この処理を overload::constant()
関数と overload::remove_constant()
関数を使ってフックできます。
These functions take a hash as an argument. The recognized keys of this hash are:
これらの関数は引数としてハッシュを取ります。 ハッシュのキーとして認識されるのは以下のものです。
- integer
-
to overload integer constants,
整数定数をオーバーロードします。
- float
-
to overload floating point constants,
浮動小数点数定数をオーバーロードします。
- binary
-
to overload octal and hexadecimal constants,
8 進および 16 進定数をオーバーロードします。
- q
-
to overload
q
-quoted strings, constant pieces ofqq
- andqx
-quoted strings and here-documents,q
-クォートされた文字列、qq
- およびqx
-クォートされた文字列の 定数片、ヒヤドキュメントをオーバーロードします。 - qr
-
to overload constant pieces of regular expressions.
正規表現の定数片をオーバーロードします。
The corresponding values are references to functions which take three arguments: the first one is the initial string form of the constant, the second one is how Perl interprets this constant, the third one is how the constant is used. Note that the initial string form does not contain string delimiters, and has backslashes in backslash-delimiter combinations stripped (thus the value of delimiter is not relevant for processing of this string). The return value of this function is how this constant is going to be interpreted by Perl. The third argument is undefined unless for overloaded q
- and qr
- constants, it is q
in single-quote context (comes from strings, regular expressions, and single-quote HERE documents), it is tr
for arguments of tr
/y
operators, it is s
for right-hand side of s
-operator, and it is qq
otherwise.
対応する値は 3 つの引数を取る関数へのリファレンスへのリファレンスです: 最初のものは定数の 初期 文字列形式、2 番目は Perl がこの定数を どのように解釈するか、3 番目は定数をどのように使うかです。 初期文字列形式は文字列デリミタを含んでおらず、バックスラッシュ-デリミタの 組み合わせでのバックスラッシュは削除されている(従ってデリミタの値は この文字列を処理するには適切ではない)ことに注意してください。 この関数の返り値はこの定数が Perl によってどのように解釈されるかです。 3 番目の引数は、オーバーロードされた q
- か qr
- 定数以外では未定義値、 (文字列、正規表現、シングルクォートヒヤドキュメントによる) シングルクォートコンテキストの場合は q
、tr
/y
演算子の引数の 場合は tr
、s
演算子の右側の場合は s
、その他では qq
になります。
Since an expression "ab$cd,,"
is just a shortcut for 'ab' . $cd . ',,'
, it is expected that overloaded constant strings are equipped with reasonable overloaded catenation operator, otherwise absurd results will result. Similarly, negative numbers are considered as negations of positive constants.
式 "ab$cd,,"
は単に 'ab' . $cd . ',,'
のショートカットなので、 オーバーロード定数文字列は妥当なオーバーロードされた結合演算子を 装備していると想定していて、さもなければ不合理な結果となります。 同様に、負数は正数の否定として扱われます。
Note that it is probably meaningless to call the functions overload::constant() and overload::remove_constant() from anywhere but import() and unimport() methods. From these methods they may be called as
import() と unimport() メソッド以外から overload::constant() や overload::remove_constant() を呼び出すのはおそらく無意味であることに 注意してください。 これらのメソッドからは、以下のようにして呼び出されます
sub import {
shift;
return unless @_;
die "unknown import: @_" unless @_ == 1 and $_[0] eq ':constant';
overload::constant integer => sub {Math::BigInt->new(shift)};
}
実装¶
What follows is subject to change RSN.
以下はすぐに変更される可能性があります。
The table of methods for all operations is cached in magic for the symbol table hash for the package. The cache is invalidated during processing of use overload
, no overload
, new function definitions, and changes in @ISA. However, this invalidation remains unprocessed until the next bless
ing into the package. Hence if you want to change overloading structure dynamically, you'll need an additional (fake) bless
ing to update the table.
すべての演算のためのメソッドのテーブルは、該当パッケージの シンボルテーブルに対するマジックとしてキャッシュされます。 このキャッシュは use overload
, no overload
, 新しい関数定義、 @ISA の変更のいずれかの処理の間に無効化されます。 しかし、この無効化はパッケージに対する次の bless
までは 実行されずに残されます。 つまり、オーバーロード構造を動的に変更したいならば、テーブルを 更新するために、(意味の無い) bless
を行なう必要があります。
(Every SVish thing has a magic queue, and magic is an entry in that queue. This is how a single variable may participate in multiple forms of magic simultaneously. For instance, environment variables regularly have two forms at once: their %ENV magic and their taint magic. However, the magic which implements overloading is applied to the stashes, which are rarely used directly, thus should not slow down Perl.)
(すべての SV 風のものは、マジックキューを持っており、マジックが キューのエントリになっています。 これによって、1 つの変数が、同時に複数のマジックの形式に 関ることができるのです。 たとえば、環境変数は普段、%ENV マジックと「汚染」マジックの 2 つの形式を一度に持っています。 しかし、オーバーロードを実装しているマジックは隠してあるものに 適用され、これはめったに直接使うことはないため、 Perl の速度を低下させないはずです。)
If an object belongs to a package using overload, it carries a special flag. Thus the only speed penalty during arithmetic operations without overloading is the checking of this flag.
オブジェクトがオーバーロードを使うパッケージに属するならば、 そのオブジェクトには、特別なフラグが用意されます。 つまり、オーバーロードされていない算術演算を行なうときの、 スピードに対する影響は、このフラグのチェックのみです。
In fact, if use overload
is not present, there is almost no overhead for overloadable operations, so most programs should not suffer measurable performance penalties. A considerable effort was made to minimize the overhead when overload is used in some package, but the arguments in question do not belong to packages using overload. When in doubt, test your speed with use overload
and without it. So far there have been no reports of substantial speed degradation if Perl is compiled with optimization turned on.
実際、use overload
が存在しなければ、オーバーロード可能な演算に 対するオーバヘッドはほとんど無く、ほとんどのプログラムで、 認識できるようなパフォーマスの低下はないはずです。 あるパッケージでオーバーロードが使われても、 対象の引数がオーバーロードを使ったパッケージに属していない場合には、 オーバヘッドの最小限にする最大限の努力が為されました。 疑わしいときには、use overload
がある場合と無い場合で、 スピードのテストをしてください。 これまでのところ、Perl が 最適化を指定してコンパイル場合には、顕著なスピードの低下の報告は あがっていません。
There is no size penalty for data if overload is not used. The only size penalty if overload is used in some package is that all the packages acquire a magic during the next bless
ing into the package. This magic is three-words-long for packages without overloading, and carries the cache table if the package is overloaded.
オーバーロードが使われないときには、データの大きさには影響しません。 あるパッケージでオーバーロードを使うときの唯一のサイズペナルティは、 全てのパッケージが次のパッケージへの bless
時に マジックを求めることです。 このマジックはオーバーロードを使わないパッケージの場合は 3 ワード長で、 オーバーロードを使うパッケージの場合はキャッシュテーブルを運びます。
Copying ($a=$b
) is shallow; however, a one-level-deep copying is carried out before any operation that can imply an assignment to the object $a (or $b) refers to, like $a++
. You can override this behavior by defining your own copy constructor (see "Copy Constructor").
$a=$b
のようなコピーは、表層的なものです。 しかし、$a++
のように、$b (または、$a) が参照するオブジェクトへの 代入を意味する演算の前に、1 層深度のコピーが行なわれます。 この動作は、 自分でコピーコンストラクタを定義することによって変更することが できます ("Copy Constructor"の項を参照してください)。
It is expected that arguments to methods that are not explicitly supposed to be changed are constant (but this is not enforced).
明示的にサポートされていないメソッドに対する引数は、 定数であることが期待されます (が、強制はされません)。
比喩の衝突¶
One may wonder why the semantic of overloaded =
is so counter intuitive. If it looks counter intuitive to you, you are subject to a metaphor clash.
なぜオーバーロードされた =
の意味論がこんなに直感的でないかを 不思議に思う人がいるかもしれません。 もし直感的でない ように見える なら、比喩の衝突に影響されています。
Here is a Perl object metaphor:
Perl のオブジェクトの比喩はこれです:
object is a reference to blessed data
オブジェクトは bless されたデータへのリファレンス
and an arithmetic metaphor:
そして算術の比喩はこれです:
object is a thing by itself.
オブジェクトはそれ自体が一つのもの。
The main problem of overloading =
is the fact that these metaphors imply different actions on the assignment $a = $b
if $a and $b are objects. Perl-think implies that $a becomes a reference to whatever $b was referencing. Arithmetic-think implies that the value of "object" $a is changed to become the value of the object $b, preserving the fact that $a and $b are separate entities.
=
をオーバーロードする 主な 問題は、$a と $b がオブジェクトのとき、 $a = $b
という代入はこれらの比喩からは異なった動作を暗示するという 事実です。 Perl 的な考え方は、$a は $b がリファレンスしている何かへのリファレンスに なることを暗示します。 算術的な考え方は、$a と $b が別々の実体であることは維持したまま、 「オブジェクト」$a の値は、オブジェクト $b の値になることを暗示します。
The difference is not relevant in the absence of mutators. After a Perl-way assignment an operation which mutates the data referenced by $a would change the data referenced by $b too. Effectively, after $a = $b
values of $a and $b become indistinguishable.
ミューテータがないなら、これは違いはありません。 Perl 式の代入の後、$a でリファレンスされているデータを変更する演算は $b でリファレンスされているデータも変更します。 事実上、$a = $b
の後では $a と $b の値は 区別ができない ものに なります。
On the other hand, anyone who has used algebraic notation knows the expressive power of the arithmetic metaphor. Overloading works hard to enable this metaphor while preserving the Perlian way as far as possible. Since it is not possible to freely mix two contradicting metaphors, overloading allows the arithmetic way to write things as far as all the mutators are called via overloaded access only. The way it is done is described in "Copy Constructor".
一方、算術記法を使っている人は誰でも、算術の比喩の表現力を知っています。 オーバーロードはこの比喩を有効にするのは難しい一方、Perl 的な方法を 出来るだけ保存した形で動作します。 2 つの矛盾する比喩を自由に混ぜることは不可能なので、 オーバーロードは 全てのミューテータがオーバーロードされた アクセス経由でのみ呼び出される限りにおいて 算術的な方法で 書くことができます。 これを行う方法は "Copy Constructor" に記述されています。
If some mutator methods are directly applied to the overloaded values, one may need to explicitly unlink other values which references the same value:
あるミューテータメソッドがオーバーロードされた値に直接適用される場合、 同じ値をリファレンスしているほかの値と 明示的にリンクを切る 必要が あるかもしれません:
$a = new Data 23;
...
$b = $a; # $b is "linked" to $a
...
$a = $a->clone; # Unlink $b from $a
$a->increment_by(4);
Note that overloaded access makes this transparent:
オーバーロードされたアクセスはこれを透過的にすることに注意してください:
$a = new Data 23;
$b = $a; # $b is "linked" to $a
$a += 4; # would unlink $b automagically
However, it would not make
しかし、以下のようにしても、
$a = new Data 23;
$a = 4; # Now $a is a plain 4, not 'Data'
preserve "objectness" of $a. But Perl has a way to make assignments to an object do whatever you want. It is just not the overload, but tie()ing interface (see "tie" in perlfunc). Adding a FETCH() method which returns the object itself, and STORE() method which changes the value of the object, one can reproduce the arithmetic metaphor in its completeness, at least for variables which were tie()d from the start.
$a の「オブジェクト性」は保存されません。 しかし、Perl にはオブジェクトへの代入を望み通りのやり方にする方法が あります。 これは単にオーバーロードではなく、tie() するインターフェースです ("tie" in perlfunc を参照してください)。 オブジェクト自身を返す FETCH() メソッドと、オブジェクトの値を変更する STORE() メソッドを追加することで、少なくとも最初から tie() されている 変数に対しては、完全性に対して算術の比喩を再現できます。
(Note that a workaround for a bug may be needed, see "BUGS".)
(このバグの回避策が必要かもしれないことに注意してください; "BUGS" を 参照してください。)
レシピ集¶
Please add examples to what follows!
どうかこれに引き続く例を追加してください!
2 面スカラ¶
Put this in two_face.pm in your Perl library directory:
これを two_face.pm として Perl ライブラリディレクトリに置きます:
package two_face; # Scalars with separate string and
# numeric values.
sub new { my $p = shift; bless [@_], $p }
use overload '""' => \&str, '0+' => \&num, fallback => 1;
sub num {shift->[1]}
sub str {shift->[0]}
Use it as follows:
以下のようにして使います:
require two_face;
my $seven = new two_face ("vii", 7);
printf "seven=$seven, seven=%d, eight=%d\n", $seven, $seven+1;
print "seven contains `i'\n" if $seven =~ /i/;
(The second line creates a scalar which has both a string value, and a numeric value.) This prints:
(2 行目は文字列値と数値の両方を持つスカラを作ります。) これは以下を出力します:
seven=vii, seven=7, eight=8
seven contains `i'
2 面リファレンス¶
Suppose you want to create an object which is accessible as both an array reference and a hash reference.
配列リファレンスとハッシュリファレンスの両方としてアクセス可能な オブジェクトを作りたいとします。
package two_refs;
use overload '%{}' => \&gethash, '@{}' => sub { $ {shift()} };
sub new {
my $p = shift;
bless \ [@_], $p;
}
sub gethash {
my %h;
my $self = shift;
tie %h, ref $self, $self;
\%h;
}
sub TIEHASH { my $p = shift; bless \ shift, $p }
my %fields;
my $i = 0;
$fields{$_} = $i++ foreach qw{zero one two three};
sub STORE {
my $self = ${shift()};
my $key = $fields{shift()};
defined $key or die "Out of band access";
$$self->[$key] = shift;
}
sub FETCH {
my $self = ${shift()};
my $key = $fields{shift()};
defined $key or die "Out of band access";
$$self->[$key];
}
Now one can access an object using both the array and hash syntax:
これで配列とハッシュの両方の文法を使ってオブジェクトにアクセスできます:
my $bar = new two_refs 3,4,5,6;
$bar->[2] = 11;
$bar->{two} == 11 or die 'bad hash fetch';
Note several important features of this example. First of all, the actual type of $bar is a scalar reference, and we do not overload the scalar dereference. Thus we can get the actual non-overloaded contents of $bar by just using $$bar
(what we do in functions which overload dereference). Similarly, the object returned by the TIEHASH() method is a scalar reference.
この例のいくつかの重要な機能に注意してください。 まず、$bar の 実際の 型はスカラリファレンスで、スカラデリファレンスは オーバーロードしていません。 従って、単に(関数の中でオーバーロードデリファレンスをしている方法である) $$bar
とすることで、実際の $bar のオーバーロードされていない中身を 得ることができます。 同様に、TIEHASH() メソッドで返されるオブジェクトはスカラリファレンスです。
Second, we create a new tied hash each time the hash syntax is used. This allows us not to worry about a possibility of a reference loop, which would lead to a memory leak.
2 番目に、ハッシュ文法が使われるたびに新しい tie されたハッシュを作ります。 これにより、メモリリークを引き起こすことになるリファレンスループの 可能性について心配しなくても良くなります。
Both these problems can be cured. Say, if we want to overload hash dereference on a reference to an object which is implemented as a hash itself, the only problem one has to circumvent is how to access this actual hash (as opposed to the virtual hash exhibited by the overloaded dereference operator). Here is one possible fetching routine:
これらの問題の両方は修正できます。 例えば、ハッシュ自身として 実装されている オブジェクトへの リファレンスに対するハッシュのデリファレンスをオーバーロードしたい場合、 回避する必要がある唯一の問題は、(オーバーロードされた デリファレンス演算子によって提供される 仮想 ハッシュではなく) この 実際の ハッシュにどうやってアクセスするかです。 これは可能なフェッチルーチンの一つです:
sub access_hash {
my ($self, $key) = (shift, shift);
my $class = ref $self;
bless $self, 'overload::dummy'; # Disable overloading of %{}
my $out = $self->{$key};
bless $self, $class; # Restore overloading
$out;
}
To remove creation of the tied hash on each access, one may an extra level of indirection which allows a non-circular structure of references:
アクセス毎に tie されたハッシュの生成をしないようにするには、 リファレンスの非円形の構造を許すための追加のレベルの間接化を行います:
package two_refs1;
use overload '%{}' => sub { ${shift()}->[1] },
'@{}' => sub { ${shift()}->[0] };
sub new {
my $p = shift;
my $a = [@_];
my %h;
tie %h, $p, $a;
bless \ [$a, \%h], $p;
}
sub gethash {
my %h;
my $self = shift;
tie %h, ref $self, $self;
\%h;
}
sub TIEHASH { my $p = shift; bless \ shift, $p }
my %fields;
my $i = 0;
$fields{$_} = $i++ foreach qw{zero one two three};
sub STORE {
my $a = ${shift()};
my $key = $fields{shift()};
defined $key or die "Out of band access";
$a->[$key] = shift;
}
sub FETCH {
my $a = ${shift()};
my $key = $fields{shift()};
defined $key or die "Out of band access";
$a->[$key];
}
Now if $baz is overloaded like this, then $baz
is a reference to a reference to the intermediate array, which keeps a reference to an actual array, and the access hash. The tie()ing object for the access hash is a reference to a reference to the actual array, so
ここでもし $bar がこのようにオーバーロードされると、$baz
は 実際の配列とアクセスハッシュへのリファレンスを保持している中間の配列への リファレンスへのリファレンスです。 アクセスハッシュへの tie() したオブジェクトは 実際の配列への リファレンスへのリファレンスなので、
-
There are no loops of references.
リファレンスのループはありません。
-
Both "objects" which are blessed into the class
two_refs1
are references to a reference to an array, thus references to a scalar. Thus the accessor expression$$foo->[$ind]
involves no overloaded operations.two_refs1
クラスに bless された両方の「オブジェクト」は配列への リファレンスへのリファレンスなので、スカラ へのリファレンスです。 従って、アクセサ式$$foo->[$ind]
はオーバーロードされた演算を 伴いません。
シンボリック計算機¶
Put this in symbolic.pm in your Perl library directory:
この symbolic.pm をあなたの Perl ライブラリディレクトリに入れてください:
package symbolic; # Primitive symbolic calculator
use overload nomethod => \&wrap;
sub new { shift; bless ['n', @_] }
sub wrap {
my ($obj, $other, $inv, $meth) = @_;
($obj, $other) = ($other, $obj) if $inv;
bless [$meth, $obj, $other];
}
This module is very unusual as overloaded modules go: it does not provide any usual overloaded operators, instead it provides the "Last Resort" operator nomethod
. In this example the corresponding subroutine returns an object which encapsulates operations done over the objects: new symbolic 3
contains ['n', 3]
, 2 + new symbolic 3
contains ['+', 2, ['n', 3]]
.
このモジュールは、オーバーロードするモジュールとしてはかなり変わっています: 通常のオーバーロード演算子は何も提供せず、その代わりに "Last Resort" 演算子 nomethod
を提供します。 この例で、対応するサブルーチンはオブジェクトに対して行われた演算を カプセル化したオブジェクトを返します: new symbolic 3
は ['n', 3]
を含み、2 + new symbolic 3
は ['+', 2, ['n', 3]]
を含みます。
Here is an example of the script which "calculates" the side of circumscribed octagon using the above package:
以下は、上述のパッケージを使って外接 8 角形の辺を「計算する」スクリプトの 例です:
require symbolic;
my $iter = 1; # 2**($iter+2) = 8
my $side = new symbolic 1;
my $cnt = $iter;
while ($cnt--) {
$side = (sqrt(1 + $side**2) - 1)/$side;
}
print "OK\n";
The value of $side is
$side の値は
['/', ['-', ['sqrt', ['+', 1, ['**', ['n', 1], 2]],
undef], 1], ['n', 1]]
Note that while we obtained this value using a nice little script, there is no simple way to use this value. In fact this value may be inspected in debugger (see perldebug), but only if bareStringify
Option is set, and not via p
command.
素晴らしい小さいスクリプトを使ってこの値を得ることは出来ましたが、 この値を 使う 単純な方法はないことに注意してください。 実際この値はデバッガ (perldebug を参照してください) で検査できますが、 bareStringify
オプションがセットされていて、p
コマンド 経由でないときのみです。
If one attempts to print this value, then the overloaded operator ""
will be called, which will call nomethod
operator. The result of this operator will be stringified again, but this result is again of type symbolic
, which will lead to an infinite loop.
もしこの値を表示しようとすると、オーバーロードされた演算子 ""
が呼び出され、これは nomethod
演算子を呼び出します。 この演算子の結果として再び文字列化が行われますが、この結果は再び symbolic
型なので、無限ループを引き起こします。
Add a pretty-printer method to the module symbolic.pm:
symbolic.pm モジュールに整形表示メソッドを追加します:
sub pretty {
my ($meth, $a, $b) = @{+shift};
$a = 'u' unless defined $a;
$b = 'u' unless defined $b;
$a = $a->pretty if ref $a;
$b = $b->pretty if ref $b;
"[$meth $a $b]";
}
Now one can finish the script by
これでスクリプトの末尾に以下のように書けます
print "side = ", $side->pretty, "\n";
The method pretty
is doing object-to-string conversion, so it is natural to overload the operator ""
using this method. However, inside such a method it is not necessary to pretty-print the components $a and $b of an object. In the above subroutine "[$meth $a $b]"
is a catenation of some strings and components $a and $b. If these components use overloading, the catenation operator will look for an overloaded operator .
; if not present, it will look for an overloaded operator ""
. Thus it is enough to use
メソッド pretty
はオブジェクト-文字列変換を行うので、 このメソッドを使って演算子 ""
をオーバーロードするのが自然です。 しかし、このようなメソッドの内部では オブジェクトの 要素 である $a や $b を整形表示する必要はありません。 上述のサブルーチンで、"[$meth $a $b]"
は、なんらかの文字列と要素 $a および $b の連結です。 もしこれらの要素がオーバーロードを使っていると、連結演算子は オーバーロードされた演算子 .
を探します; もし存在しなければ、 オーバーロードされた演算子 ""
を探します。 従って以下を使えば十分です
use overload nomethod => \&wrap, '""' => \&str;
sub str {
my ($meth, $a, $b) = @{+shift};
$a = 'u' unless defined $a;
$b = 'u' unless defined $b;
"[$meth $a $b]";
}
Now one can change the last line of the script to
これでスクリプトの末尾を以下のように書き換えられます
print "side = $side\n";
which outputs
以下のように出力されます
side = [/ [- [sqrt [+ 1 [** [n 1 u] 2]] u] 1] [n 1 u]]
and one can inspect the value in debugger using all the possible methods.
そして全ての可能なメソッドを使ってデバッガで値を検査できます。
Something is still amiss: consider the loop variable $cnt of the script. It was a number, not an object. We cannot make this value of type symbolic
, since then the loop will not terminate.
まだ何かがおかしいです: スクリプトのループ変数 $cnt を考えてみます。 これは数値であり、オブジェクトではありません。 この値の型を symbolic
にはできません; なぜならそうするとループが 終了しないからです。
Indeed, to terminate the cycle, the $cnt should become false. However, the operator bool
for checking falsity is overloaded (this time via overloaded ""
), and returns a long string, thus any object of type symbolic
is true. To overcome this, we need a way to compare an object to 0. In fact, it is easier to write a numeric conversion routine.
確かに、循環を終了させるために、$cnt は偽になる必要があります。 しかし、偽かどうかをチェックする演算子 bool
が (今回はオーバーロードされた ""
経由で) オーバーロードされていて、 長い文字列を返すので、型 symbolic
のあらゆるオブジェクトは真です。 これを乗り越えるために、オブジェクトを 0 と比較する方法が必要です。 実際、これは数値変換ルーチンを書くより簡単です。
Here is the text of symbolic.pm with such a routine added (and slightly modified str()):
以下はそのようなルーチンを追加した (そして str() を少し修正した) symbolic.pm の内容です:
package symbolic; # Primitive symbolic calculator
use overload
nomethod => \&wrap, '""' => \&str, '0+' => \#
sub new { shift; bless ['n', @_] }
sub wrap {
my ($obj, $other, $inv, $meth) = @_;
($obj, $other) = ($other, $obj) if $inv;
bless [$meth, $obj, $other];
}
sub str {
my ($meth, $a, $b) = @{+shift};
$a = 'u' unless defined $a;
if (defined $b) {
"[$meth $a $b]";
} else {
"[$meth $a]";
}
}
my %subr = ( n => sub {$_[0]},
sqrt => sub {sqrt $_[0]},
'-' => sub {shift() - shift()},
'+' => sub {shift() + shift()},
'/' => sub {shift() / shift()},
'*' => sub {shift() * shift()},
'**' => sub {shift() ** shift()},
);
sub num {
my ($meth, $a, $b) = @{+shift};
my $subr = $subr{$meth}
or die "Do not know how to ($meth) in symbolic";
$a = $a->num if ref $a eq __PACKAGE__;
$b = $b->num if ref $b eq __PACKAGE__;
$subr->($a,$b);
}
All the work of numeric conversion is done in %subr and num(). Of course, %subr is not complete, it contains only operators used in the example below. Here is the extra-credit question: why do we need an explicit recursion in num()? (Answer is at the end of this section.)
全ての数値変換の作業は %subr と num() で行われます。 もちろん、%subr は不完全で、以下の例で使われる演算子のみを含んでいます。 これは追加点の質問です: なぜ num() で明示的な再帰が必要なのでしょう? (答えはこの章の最後にあります。)
Use this module like this:
このモジュールは以下のようにして使います:
require symbolic;
my $iter = new symbolic 2; # 16-gon
my $side = new symbolic 1;
my $cnt = $iter;
while ($cnt) {
$cnt = $cnt - 1; # Mutator `--' not implemented
$side = (sqrt(1 + $side**2) - 1)/$side;
}
printf "%s=%f\n", $side, $side;
printf "pi=%f\n", $side*(2**($iter+2));
It prints (without so many line breaks)
これは(たくさんの改行を除くと)以下のものを表示します
[/ [- [sqrt [+ 1 [** [/ [- [sqrt [+ 1 [** [n 1] 2]]] 1]
[n 1]] 2]]] 1]
[/ [- [sqrt [+ 1 [** [n 1] 2]]] 1] [n 1]]]=0.198912
pi=3.182598
The above module is very primitive. It does not implement mutator methods (++
, -=
and so on), does not do deep copying (not required without mutators!), and implements only those arithmetic operations which are used in the example.
上述のモジュールはとても原始的なものです。 ミューテータメソッド (++
, -=
and so on) を実装していませんし、 ディープコピー(ミューテータがなければ不要です!)もできませんし、 例で使う算術演算しか実装していません。
To implement most arithmetic operations is easy; one should just use the tables of operations, and change the code which fills %subr to
ほとんどの算術演算の実装は簡単です; 単に演算のテーブルを使って、 %subr を埋めているコードを以下のように変更するだけです
my %subr = ( 'n' => sub {$_[0]} );
foreach my $op (split " ", $overload::ops{with_assign}) {
$subr{$op} = $subr{"$op="} = eval "sub {shift() $op shift()}";
}
my @bins = qw(binary 3way_comparison num_comparison str_comparison);
foreach my $op (split " ", "@overload::ops{ @bins }") {
$subr{$op} = eval "sub {shift() $op shift()}";
}
foreach my $op (split " ", "@overload::ops{qw(unary func)}") {
print "defining `$op'\n";
$subr{$op} = eval "sub {$op shift()}";
}
Due to "Calling Conventions for Mutators", we do not need anything special to make +=
and friends work, except filling +=
entry of %subr, and defining a copy constructor (needed since Perl has no way to know that the implementation of '+='
does not mutate the argument, compare "Copy Constructor").
"Calling Conventions for Mutators" によって、%subr の +=
エントリを 埋めることと、コピーコンストラクタを定義すること (これは '+='
の実装が 引数を変更しないことを Perl が知る方法はないために必要です; "Copy Constructor" と比較してください) のほかに、+=
とその親類が 動作するために必要なことは何もありません。
To implement a copy constructor, add '=' => \&cpy
to use overload
line, and code (this code assumes that mutators change things one level deep only, so recursive copying is not needed):
コピーコンストラクタを実行するには、use overload
の行に '=' => \&cpy
を追加して、以下のコードを書きます (このコードは、ミューテータは 1 レベルの深さのみの変更を行うので、 再帰的コピーは不要であることを仮定しています):
sub cpy {
my $self = shift;
bless [@$self], ref $self;
}
To make ++
and --
work, we need to implement actual mutators, either directly, or in nomethod
. We continue to do things inside nomethod
, thus add
++
と --
が動作するようにするには、実際のミューテータを、 直接あるいは nomethod
で実装する必要があります。 私達は物事を nomethod
で続けると決めたので、以下を
if ($meth eq '++' or $meth eq '--') {
@$obj = ($meth, (bless [@$obj]), 1); # Avoid circular referencen
return $obj;
}
after the first line of wrap(). This is not a most effective implementation, one may consider
wrap() の最初の行の後に追加します。 これは最も効果的な実装というわけではないので、代わりに
sub inc { $_[0] = bless ['++', shift, 1]; }
instead.
とすることを考えるかもしれません。
As a final remark, note that one can fill %subr by
最後の意見として、以下のようなもので %subr を埋めることができることに 注意してください
my %subr = ( 'n' => sub {$_[0]} );
foreach my $op (split " ", $overload::ops{with_assign}) {
$subr{$op} = $subr{"$op="} = eval "sub {shift() $op shift()}";
}
my @bins = qw(binary 3way_comparison num_comparison str_comparison);
foreach my $op (split " ", "@overload::ops{ @bins }") {
$subr{$op} = eval "sub {shift() $op shift()}";
}
foreach my $op (split " ", "@overload::ops{qw(unary func)}") {
$subr{$op} = eval "sub {$op shift()}";
}
$subr{'++'} = $subr{'+'};
$subr{'--'} = $subr{'-'};
This finishes implementation of a primitive symbolic calculator in 50 lines of Perl code. Since the numeric values of subexpressions are not cached, the calculator is very slow.
これは、原始的なシンボリック計算機を 50 行の Perl コードで実装完了します。 部分式の数値はキャッシュされないので、計算機はとても遅いです。
Here is the answer for the exercise: In the case of str(), we need no explicit recursion since the overloaded .
-operator will fall back to an existing overloaded operator ""
. Overloaded arithmetic operators do not fall back to numeric conversion if fallback
is not explicitly requested. Thus without an explicit recursion num() would convert ['+', $a, $b]
to $a + $b
, which would just rebuild the argument of num().
これが課題の答えです: str() の場合、オーバーロードした .
演算子は すでに存在するオーバーロードした演算子 ""
にフォールバックするので、 明示的な再帰をする必要はありません。 オーバーロードした算術演算子は、明示的に fallback
が要求されない限り フォールバック しません 。 従って、明示的な再帰なしでは num() は ['+', $a, $b]
を $a + $b
に 変換し、これは単に num() の引数を再ビルドします。
If you wonder why defaults for conversion are different for str() and num(), note how easy it was to write the symbolic calculator. This simplicity is due to an appropriate choice of defaults. One extra note: due to the explicit recursion num() is more fragile than sym(): we need to explicitly check for the type of $a and $b. If components $a and $b happen to be of some related type, this may lead to problems.
もしなぜ str() と num() で変換のデフォルトが異なるかが不思議なら、 シンボリック計算機を書くのがどれだけ簡単だったかに注意してください。 この簡単さは適切なデフォルトの選択によるものです。 もう一つ追加の注意: 明示的な再帰によって、num() は sym() より壊れやすいです: $a と $b の型を明示的にチェックする必要があります。 もし $a と $b がたまたま関係のある型の場合、これは問題を引き起こすかも しれません。
Really symbolic calculator¶
(本当に シンボリックな計算機)
One may wonder why we call the above calculator symbolic. The reason is that the actual calculation of the value of expression is postponed until the value is used.
なぜ私達が上述の計算機をシンボリックと呼ぶのかを疑問に思う人も いるかもしれません。 その理由は、式の値の実際の計算はその値が 使われる まで延期されます。
To see it in action, add a method
実行中に見るために、以下のメソッドを
sub STORE {
my $obj = shift;
$#$obj = 1;
@$obj->[0,1] = ('=', shift);
}
to the package symbolic
. After this change one can do
パッケージ symbolic
に追加します。 この変更の後、以下のように出来て
my $a = new symbolic 3;
my $b = new symbolic 4;
my $c = sqrt($a**2 + $b**2);
and the numeric value of $c becomes 5. However, after calling
$c の数値は 5 になります。 しかし、以下の呼出し後、
$a->STORE(12); $b->STORE(5);
the numeric value of $c becomes 13. There is no doubt now that the module symbolic provides a symbolic calculator indeed.
$c の数値は 13 になります。 これでモジュール symbolic はまさに シンボリック 計算機を提供します。
To hide the rough edges under the hood, provide a tie()d interface to the package symbolic
(compare with "Metaphor clash"). Add methods
フードの中の荒いエッジを隠すために、パッケージ symbolic
へ tie() したインターフェースを提供します ("Metaphor clash" と比較してください)。 メソッドを追加します
sub TIESCALAR { my $pack = shift; $pack->new(@_) }
sub FETCH { shift }
sub nop { } # Around a bug
(the bug is described in "BUGS"). One can use this new interface as
(このバグは "BUGS" に記述されています)。 この新しいインタフェースは以下のようにして使えます
tie $a, 'symbolic', 3;
tie $b, 'symbolic', 4;
$a->nop; $b->nop; # Around a bug
my $c = sqrt($a**2 + $b**2);
Now numeric value of $c is 5. After $a = 12; $b = 5
the numeric value of $c becomes 13. To insulate the user of the module add a method
ここで $c の数値は 5 です。 $a = 12; $b = 5
の後、$c の数値は 13 になります。 モジュールのユーザーを分離す津ために、メソッドを追加します
sub vars { my $p = shift; tie($_, $p), $_->nop foreach @_; }
Now
ここで
my ($a, $b);
symbolic->vars($a, $b);
my $c = sqrt($a**2 + $b**2);
$a = 3; $b = 4;
printf "c5 %s=%f\n", $c, $c;
$a = 12; $b = 5;
printf "c13 %s=%f\n", $c, $c;
shows that the numeric value of $c follows changes to the values of $a and $b.
とすると、$c の数値は $a と $b の値の変更に従います。
作者¶
Ilya Zakharevich <[email protected]>.
DIAGNOSTICS¶
When Perl is run with the -Do switch or its equivalent, overloading induces diagnostic messages.
Perl を -Do スイッチか同等のものを使って起動すると、 オーバーロードによって診断メッセージを引き起こします。
Using the m
command of Perl debugger (see perldebug) one can deduce which operations are overloaded (and which ancestor triggers this overloading). Say, if eq
is overloaded, then the method (eq
is shown by debugger. The method ()
corresponds to the fallback
key (in fact a presence of this method shows that this package has overloading enabled, and it is what is used by the Overloaded
function of module overload
).
Perl デバッガの m
コマンド (perldebug を参照してください) を 使うことで、どの演算がオーバーロードされているか (そしてどの祖先が このオーバーロードを引き起こしているか) を推論することができます。 例えば、eq
がオーバーロードされていると、メソッド (eq
が デバッガによって表示されます。 メソッド ()
は fallback
キーに対応します (実際このメソッドの存在は、このパッケージはオーバーロードが有効になっていて、 overload
モジュールの Overloaded
関数で使われていることを 示しています)。
The module might issue the following warnings:
このモジュールは以下の警告を出すことがあります:
- Odd number of arguments for overload::constant
-
(W) The call to overload::constant contained an odd number of arguments. The arguments should come in pairs.
(W) 奇数の数の引数で overload::constant を呼び出しました。 引数はペアになっている必要があります。
- `%s' is not an overloadable type
-
(W) You tried to overload a constant type the overload package is unaware of.
(W) オーバーロードパッケージが知らない定数型をオーバーロードしようとしました。
- `%s' is not a code reference
-
(W) The second (fourth, sixth, ...) argument of overload::constant needs to be a code reference. Either an anonymous subroutine, or a reference to a subroutine.
(W) overload::constant の 2 番目 (4 番目、6 番目, ...) の引数はコード リファレンスである必要があります。 無名サブルーチンか、サブルーチンへのリファレンスです。
バグ¶
Because it is used for overloading, the per-package hash %OVERLOAD now has a special meaning in Perl. The symbol table is filled with names looking like line-noise.
オーバーロードに使用されるため、Perl では、ハッシュ %OVERLOAD は、 パッケージごとに特別な意味を持つことになります。 シンボルテーブルはごみのように見える名前で埋められます。
For the purpose of inheritance every overloaded package behaves as if fallback
is present (possibly undefined). This may create interesting effects if some package is not overloaded, but inherits from two overloaded packages.
継承の目的のために、全てのオーバーロードされたパッケージは (未定義かもしれない) fallback
が存在するかのように振る舞います。 これは、あるパッケージがオーバーロードしていないけれども、 2 つのオーバーロードしたパッケージを継承しているという場合に、 興味深い効果を作り出します。
Relation between overloading and tie()ing is broken. Overloading is triggered or not basing on the previous class of tie()d value.
オーバーロードと tie() の関係は壊れています。 オーバーロードは tie() された値の 以前の クラスによって 引き起こされるかどうかが決まります。
This happens because the presence of overloading is checked too early, before any tie()d access is attempted. If the FETCH()ed class of the tie()d value does not change, a simple workaround is to access the value immediately after tie()ing, so that after this call the previous class coincides with the current one.
これは、オーバーロードの存在のチェックが早すぎて、tie() したアクセスを 試みる前に行われるために起こります。 もし tie() された値の FETCH() されたクラスが変更していないなら、簡単な 回避法は tie() した直後に値にアクセスすることで、この呼び出しの後 以前の クラスは現在のものと同期します。
Needed: a way to fix this without a speed penalty.
必要: 速度に影響を与えることなくこれを修正する方法。
Barewords are not covered by overloaded string constants.
裸の単語はオーバーロードされた文字列定数の対象となりません。
This document is confusing. There are grammos and misleading language used in places. It would seem a total rewrite is needed.
このドキュメントは混乱しています。 あちこちに誤解しやすい文章があります。 完全な書き直しが必要です。