Sun, 19 Oct 2008

Custom Operators


Permanent link

NAME

"Perl 5 to 6" Lesson 13 - Custom Operators

LAST UPDATED

2015-02-26

SYNOPSIS

    multi sub postfix:<!>(Int $x) {
        my $factorial = 1;
        $factorial *= $_ for 2..$x;
        return $factorial;
    }
    
    say 5!;                     # 120

DESCRIPTION

Operators are functions with unusual names, and a few additional properties like precedence and associativity. Perl 6 usually follows the pattern term infix term, where term can be optionally preceded by prefix operators and followed by postfix or postcircumfix operators.

    1 + 1               infix
    +1                  prefix
    $x++                postfix
    <a b c>             circumfix
    @a[1]               postcircumfix

Operator names are not limited to "special" characters, they can contain anything except whitespace.

The long name of an operator is its type, followed by a colon and a string literal or list of the symbol or symbols, for example infix:<+> is the the operator in 1+2. Another example is postcircumfix:<[ ]>, which is the operator in @a[0].

With this knowledge you can already define new operators:

    multi sub prefix:<€> (Str $x) {
        2 *  $x;
    }
    say €4;                         # 8

Precedence

In an expression like $a + $b * $c the infix:<*> operator has tighter precedence than infix:<+>, which is why the expression is evaluated as $a + ($b * $c).

The precedence of a new operator can be specified in comparison to to existing operators:

    multi sub infix:<foo> is equiv(&infix:<+>) { ...  }
    mutli sub infix:<bar> is tighter(&infix:<+>) { ... }
    mutli sub infix:<baz> is looser(&infix:<+>) { ... }

Associativity

Most infix operators take only two arguments. In an expression like 1 / 2 / 4 the associativity of the operator decides the order of evaluation. The infix:</> operator is left associative, so this expression is parsed as (1 / 2) / 4. for a right associative operator like infix:<**> (exponentiation) 2 ** 2 ** 4 is parsed as 2 ** (2 ** 4).

Perl 6 has more associativities: none forbids chaining of operators of the same precedence (for example 2 <=> 3 <=> 4 is forbidden), and infix:<,> has list associativity. 1, 2, 3 is translated to infix:<,>(1; 2; 3). Finally there's the chain associativity: $a < $b < $c translates to ($a < $b) && ($b < $c).

    multi sub infix:<foo> is tighter(&infix:<+>)
                          is assoc('left')
                          ($a, $b) {
        ...
    }

"Overload" existing operators

Most (if not all) existing operators are multi subs, and can therefore be customized for new types. Adding a multi sub is the way of "overloading" operators.

    class MyStr { ... }
    multi sub infix:<~>(MyStr $this, Str $other) { ... }

This means that you can write objects that behave just like the built in "special" objects like Str, Int etc.

MOTIVATION

Allowing the user to declare new operators and "overload" existing ones makes user defined types just as powerful and useful as built in types. If the built in ones turn out to be insufficient, you can replace them with new ones that better fit your situation, without changing anything in the compiler.

It also removes the gap between using a language and modifying the language.

SEE ALSO

"language/functions#Defining%20Operators" in doc.perl6.org

http://design.perl6.org/S06.html#Operator_overloading

If you are interested in the technical background, ie how Perl 6 can implement such operator changes and other grammar changes, read http://perlgeek.de/en/article/mutable-grammar-for-perl-6.

[/perl-5-to-6] Permanent link