Blog::kobaken

prove t/foo/bar/baz.t

Perlのインタフェース実装をした

吉祥寺.pm #17 で話した内容です。吉祥寺.pm 楽しかったです! ちなむと吉祥寺.pmのフィードバックはこちらです。楽しかった。

本題

Perlのインタフェース実装をしました。雰囲気はJavaとかのインタフェースです。 次のキャプチャにあるように、コンパイル時に色々教えてくれて嬉しいです。

asciicast

使い方

まず、インタフェースの定義は次のようにします。 例えば、fun hello(Str $msg) :Return(Str); と書けば、引数はStr $msg、返り値の型はStrな関数helloを宣言します。

package IFoo {
    use Function::Interface;
    use Types::Standard -types;
 
    fun hello(Str $msg) :Return(Str);
 
    fun add(Int $a, Int $b) :Return(Int);
}

次に、インタフェースの実装は次のようにします。 Function::ParametersFunction::Returnを用いて関数の実装をします。

package Foo {
    use Function::Interface::Impl qw(IFoo);
    use Types::Standard -types;
 
    fun hello(Str $msg) :Return(Str) {
        return "HELLO $msg";
    }
 
    fun add(Int $a, Int $b) :Return(Int) {
        return $a + $b;
    }
}

そして、ImplOf['IFoo']のようにインタフェースの型指定します。 実装に依存しなくなって、嬉しいですね。

package FooService {
    use Function::Interface::Types qw(ImplOf);
    use Function::Parameters;
    use Function::Return;
    use Mouse;
 
    use aliased 'IFoo';
 
    fun greet(ImplOf[IFoo] $foo) :Return() {
        print $foo->hello;
        return;
    }
}
 
my $foo_service = FooService->new;
my $foo = Foo->new; # implements of IFoo
 
$foo_service->greet($foo);

奇妙ですが、面白いですね!

仕組み

簡単ですが、次のような感じです。

  • Function::Interface は、Keyword::Simple + PPR で文法を拡張しています。Deparseすると、抽象関数のメタ情報を保存していることがわかります。
  • Function::Interface::Impl は、保存したインタフェースのメタ情報と、Function::Parameters、Function::Returnを用いて取得できる実装のメタ情報を付き合わせて、エラー判定しています。
  • ImplOf は、Type::Tinyでparameterizeして型を定義しています。

Perlの自由さが感じられて楽しいですね。機会があれば、詳解したいです。

さいごに

遊んでくれる人がいると嬉しいです。以上です!

github.com