鳩舎

レースしない

Perl 6 の does と ^add_role の違い

@kuzuha から素敵情報が届いたので。

面白い。試す。

> class c {};
(c)
> role r {method greet { say "hello"; }};
(r)
> my $a = c.new.^add_role(r);
(r)
> $a.greet()
hello

いい感じだ。

ただ my $a = c.new.^add_role(r); の時の (r) という返り値がどうも気にかかる。

does の方を使ってみると結果が違う。

> my $b = c.new does r;
c+{r}.new()

これはこれは……

> class c {method hello { say "hello"; } };
(c)
> role r {method hi { say "hi"; } };
(r)
> (c.new does r).hello();
hello

動く

> (c.new.^add_role(r)).hello()
Method 'hello' not found for invocant of class 'r'

動かない。 oh...

ついでに比較もしておく。

> my $a = (c.new);
c.new()
> my $b = $a does r;
c+{r}.new()
> $a eq $b
True
> $a
c+{r}.new()

does は破壊的操作なので同値になる。まぁ、そりゃそう。

> my $d = $a.^add_role(r);
(r)
> $a eq $d
use of uninitialized value of type r in string context  in any  at src/gen/Metamodel.nqp:1352

False

つらたん。

そんでもって動的に role を追加する方法を考えるとこんな感じになる。

> class c {};
(c)
> role r {};
(r)
> my $instance = c.new
c.new()
> my $role = r
(r)
> $instance does $role
c+{r}.new()

当たり前だけど does は破壊的操作なので取り外せない。 unextend 的な C 拡張か、言語仕様の拡張を作る必要がある。