Perl 6 の関数は sub だけじゃない

sub と言えば Perl、 Perl と言えば sub ですが、 Perl 6 の関数定義には sub 以外にも色々あり、それぞれに役割が異なっています。1つ1つ見ていきましょう。

# sub

`sub` は Perl 5 の sub と同じく、モジュールレベルの関数を定義します。

```
sub foobar { say 'ok' }
foobar; # => ok
```

## my sub, our sub

単に `sub` と書くと `my sub` の省略だと見なされます。 `my sub` で定義した関数はモジュールの外からは見えません。関数をモジュール外から呼び出せるようにするには明示的に `our sub` で定義します。

```
module Foo {
    sub bar { say 'ok' }
    my sub my_bar { say 'ok' }
    our sub our_bar { say 'ok' }
}

Foo::bar; # => error: Could not find symbol '&bar'
Foo::my_bar; # => error: Could not find symbol '&my_bar'
Foo::our_bar; # => ok
```

## multi sub

`multi sub` はマルチディスパッチに対応した関数を定義します。マルチディスパッチは C++ や Java でいうオーバーロードを動的に実現する機構で、引数の型や値によって関数を呼び分けることができます。

```
multi sub foo(Int $int) { say 'int' }
multi sub foo(Str $str) { say 'str' }

foo(42); # => int
foo('the answer'); # => str
```

## proto sub

`proto sub` は `multi sub` で多重定義した同名の関数に共通する性質を定義します。たとえば関数本体が実行される前にコードを差し込むことができます。

```
multi sub foo(Int $int) { say 'int' }
multi sub foo(Str $str) { say 'str' }
proto sub foo(|) { print 'I haz '; {*} } # `{*}` は適切な multi sub の本体に置き換わる

foo(42); # => I haz int
foo('the answer'); # => I haz str
```

## anon sub
`anon sub {}` 式は匿名関数オブジェクトを作ることができます。

```
my $f = anon sub foo { say 'foo' };
$f(); # => foo
```

`sub {}` 式で作れる**無名**関数オブジェクトと違い、**匿名**関数オブジェクトには名前がついています（ややこしいですね）。関数オブジェクトに名前をつけておくとエラーが起きたときバックトレースに関数名が表示されます。デバッグの助けになるでしょう。

```
(anon sub foo { die 'ouch!' })(); # => error: ouch! in sub foo at /path/to/script:1
#                                                      ^^^^^^^ 匿名：名前あり
(sub { die 'ouch!' })(); # => error: ouch! in sub  at /path/to/script:1
#                                             ^^^^ 無名：名前なし
```

なお `sub {}` 式で名前つき関数オブジェクトを作ると関数定義もされてしまうので注意が必要です。

```
(sub foo { say 'foo' })(); #=> foo
foo; # => foo
```

# method

`method` はその名のとおりメソッドを定義します。

```
class Klass {
    method meth { say 'ok' }
}
Klass.meth; # => ok
```

 Perl 6 にはクラスメソッドとインスタンスメソッドの違いはありません。クラスメソッドとして呼び出した場合は `self` がクラスオブジェクトになります。クラスオブジェクトは未定義値扱いなので、 `self.defined` の真偽を見ればクラスメソッドとして呼ばれたかどうかが分かります。

```
class Klass {
    method meth {
        if self.defined { say 'called as instance method' }
        else { say 'called as class method' }
    }
}

Klass.new.meth; # => called as instance method
Klass.meth; # => called as class method
```

`self` が未定義値であるかどうかでマルチディスパッチすることもできます。

```
class Klass {
    multi method meth(Mu:D:) { say 'called as instance method' }
    multi method meth(Mu:U:) { say 'called as class method' }
}

Klass.new.meth; # => called as instance method
Klass.meth; # => called as class method
```

## method ! (private method)

プライベートメソッドを定義するにはメソッド名の前に `!` をつけます。プライベートメソッドを呼び出すには `.` ではなく `!` を使って `self!meth()` のようにします。

```
class Klass {
    method pub { say 'pub and ' ~ self!priv }
    method !priv { 'priv' }
}

Klass.pub; # => pub and priv
Klass.priv; # => error: No such method 'priv' for invocant of type 'Klass'
```

## submethod

`submethod` は継承されないメソッドを定義します。必ずオーバーライドしなければならないメソッドを定義するときなどに使います。

```
class Base {
    method meth { say 'meth and' ~ self.submeth }
    method submeth { 'submeth' }
}

class DerivedWithSubmeth is Base {
    submethod submeth { 'another submeth' }
}

class DerivedWithoutSubmeth is Base {}

Base.new.meth; # => meth and submeth
DerivedWithSubmeth.meth; # => meth and another submeth
DerivedWithoutSubmeth.meth; # => error: No such method 'submeth' for ...
```