09 March 2005
This post may be outdated due to it was written on 2005. The links may be broken. The code may be not working anymore. Leave comments if needed.
English version: http://dev.perl.org/perl6/synopsis/S13.html


Synopsis 13: Overloading

纲要 13:重载


Larry Wall <[email protected]>


  Maintainer: Larry Wall 
  Date: 2 Nov 2004
  Last Modified: 2 Dec 2004
  Number: 13
  Version: 3

Overview 概述

This synopsis discusses those portions of Apocalypse 12 that ought to have been in Apocalypse 13.

本纲要用以讨论启示录 12 中应该位于启示录 13 的部分。

Multiple dispatch 多重分派

The overloading mechanism of Perl 5 has been superseded by Perl 6's multiple dispatch mechanism. Nearly all internal functions are defined as multi subs or multi methods on generic types. Built-in operators are merely oddly named functions with an alternate call syntax. All you have to do to overload them is to define your own multi subs and methods that operate on arguments with more specific types.

Perl 5 中的重载机制将被 Perl 6 中的多重分派机制所取代。几乎所有的内部函数 都是由传递一般类的 multi 子程序或 multi 方法所定义。内置运算符不过是 奇怪的函数名加上不同的调用语法而已。要重载它们的话,你只需要定义你自己的 multi 子程序和方法,然后通过指定特定类型的参数来达成目的。

For unary operators, this makes little effective difference, but for binary operators, multiple dispatch fixes the Perl 5 problem of paying attention only to the type of the left argument. Since both argument types are used in deciding which routine to call, there is no longer any trickery involving swapping the arguments to use the right argument's type instead of the left one. And there's no longer any need to examine a special flag to see if the arguments were reversed.

对于一元运算符,没有什么大变化。但对于二元运算符,多重分派修正了 Perl 5 中仅仅对左边的参数类型加以注意的错误。因为在多重分派中所有的参数类型 对你要调用哪个程序都有影响,所以再也不需要通过调换参数,用右边参数类型来代替 左边而达成调用欺骗。而且再也不需要检查一个特定标记来决定这个参数是否保留。

For much more about multiple dispatch, see A12.

需要更多关于多重分派的信息,请参考 A12.

Syntax 语法

There is no longer any special use overload syntax separate from the declarations of the multi routines themselves. To overload an existing built-in sub, say something like:

除了 multi 程序申明外,再也没有任何特殊的 use overload 语法。 如果要重载一个已存在的内建子程序,这用这么写:

    multi sub *uc (TurkishStr $s) {...}

Now if you call uc() on any Turkish string, it will call your function rather than the built-in one. Putting the multi into the * namespace makes it show up in everyone's packages, but as long as no one else defines a version of uc on TurkishStr, there's no collision. The types of the invocants are included in the ``long name'' of any multi sub or method.

现在如果你用 土耳其/Turkish 字符串来调用 uc, 那么它将调用你刚写的函数 而不是内建函数。将 multi 放在 * 命名空间可以让此子程序在所有人的 包/package 中使用,只用没有其他人也定义了一个 TurkishStr 版本的 uc ,那就没有任何冲突。 调用的类别将保护在任何 multi 子程序或方法的“长名”内。

If you want to overload string concatenation for Arabic strings so you can handle various ligatures, you can say:

如果你想对 阿拉伯语/Arabic 字符串 重载字符串联以便处理不同的 连字/ligatures, 你可以这么写:

    multi sub *infix:<~>(ArabicStr $s1, ArabicStr $s2) {...}
    multi sub *infix:<~>(Str $s1, ArabicStr $s2) {...}
    multi sub *infix:<~>(ArabicStr $s1, Str $s2) {...}

Ordinary methods can be turned into multi methods within the class definition:

一般方法可以在类定义中转换成 多重/multi 方法:

    class MyNum {
        multi method abs(MyNum $x) {...}

Likewise operators on your new type can appear in the class:


    class MyNum {
        multi method prefix:<+> (MyNum $x) {...} # what we do in numeric context
        multi method prefix:<~> (MyNum $x) {...} # what we do in string context
        multi method prefix: (MyNum $x) {...} # what we do in boolean context

Binary operators may be declared as commutative:


    multi sub infix:<+> (Us $us, Them $them) is commutative { myadd($us,$them) }

That's equivalent to:


    multi sub infix:<+> (Us $us, Them $them) { myadd($us,$them) }
    multi sub infix:<+> (Them $them, Us $us) { myadd($us,$them) }

Note the lack of * on those definitions. That means this definition of addition is only in effect within the scope of the package in which infix:<+> is defined. Similar constraints apply to lexically scoped multi subs. Generally you want to put your multi subs into the * space, however, so that they work everywhere.

注意这些定义中都没有 *. 这表示新增的这个定义只对 infix:<+> 所定义的 包作用域有效。相同的约束作用于在词法作用域的 多重/multi 子程序。不过通常你应该 将 多重/multi 子程序放在 * 空间内,这样它们能在任何地方使用。

The use overload syntax had one benefit over Perl 6's syntax in that it was easy to alias several different operators to the same service routine. This can easily be handled with Perl 6's aliasing:

use overload 语法相较于 Perl 6 语法还有个优点,它可以简单的使用别名让许多不同 的运算符使用同一个服务程序。通过 Perl 6 的别名,这也可以轻松搞定:

    multi sub unimpl (MyFoo $x) { upchuck(); }
    &infix:<+> ::= &unimpl;
    &infix:<-> ::= &unimpl;
    &infix:<*> ::= &unimpl;
    &infix: ::= &unimpl;

Fallbacks 预设机制

Dispatch is based on a routine's signature declaration without regard to whether the routine is defined yet. If an attempt is made to dispatch to a declared but undefined routine, Perl will redispatch to AUTOSUBDEF or AUTOMETHDEF as appropriate to define the routine. This provides a run-time mechanism for fallbacks. By default, these declarations are taken at face value and do not specify any underlying semantics. As such, they're a ``shallow'' interpretation.

分派机制只是基于程序的声明信号,而不管这个程序是否已经被定义。如果试图分派 一个已声明却未定义的程序, Perl 将重分派到 AUTOSUBDEFAUTOMETHDEF 来定义这个程序。这就提供了一个运行时的预设机制。默认这些声明将根据外表值来 判断而不指定任何潜在的语意。也就是说,这是种“浅层”解释。

However, sometimes you want to specify a ``deep'' interpretation of your operators. That is, you're specify the abstract operation, which may be used by various shallow operators. Any deep multi declarations will be ``amplified'' into all the shallow operators that can be logically based on it. If you say:

但是,有时候你需要对你的运算符指定一个“深层”解释。也就是说,你指定个抽象 运算符,它可能被多个浅层操作符所调用。任何一个深层多重声明都会被“扩大”到所有 逻辑上基于它的浅层运算符。

    multi sub infix:<%> (Us $us, Them $them) is deep { mymod($us,$them) }



    multi sub infix:<%=> (Us $us, Them $them) { $us = $us % $them }

is also generated for you (unless you define it yourself). The mappings of magical names to sub definitions is controlled by the %?DEEPMAGIC compiler hash. Pragmas can influence the contents of this hash over a lexical scope, so you could have different policies on magical autogeneration. The default mappings correspond to the standard fallback mappings of Perl 5 overloading.

也会被产生(除非你自己定义它)。 魔术名字(magical names)到子程序声明的映射由 %?DEFPMAGIC 编译器散列 所约束。编译指示(Pargmas)能在词法作用域范围内影响这个散列的值,所以你 可以在魔术自动生成上有很多不同的策略。默认的映射与 Perl 5 重载的标准预设 映射相应。

blog comments powered by Disqus