Perl 6 オブジェクト指向 プログラミング YAPC::Asia TOKYO 2013 2013/09/21 risou
Jul 05, 2015
Perl 6オブジェクト指向プログラミング
YAPC::Asia TOKYO 20132013/09/21risou
※注意ここでのPerl 6の説明は簡素化のため、厳密には正しくない表現も含まれます。
(もしくは私の間違いです)
お話する人
• risou ( @risou )• 職業プログラマではない• 普段は Java とか Haskell とか書いてます• たまに Perl 入学式にいたりいなかったり• 昨夜、銀歯がとれました
今喋ってるのはこんな人です。
本日のお題
• Perl 6 でオブジェクト指向プログラミング今日喋るのはこんなことです。
本日のお題
• Perl 6 でオブジェクト指向プログラミング今日喋るのはこんなことです。
もっと言うと……
• Perl でのオブジェクト指向• Perl 6 でのオブジェクト指向• Perl と Perl 6 の違いとかに間接的に言及するかも
オブジェクト指向
オブジェクト指向とは
• データの構造と振舞いをオブジェクトとして扱う• オブジェクト間でのメッセージのやりとりでシステムを構成する
• 様々なプログラミング言語がサポートしている• Smalltalk / C++ / Java / Perl / Ruby / ...
ご存知の方も多いかと思いますが……
オブジェクト指向の特徴
• カプセル化• ポリモーフィズム• 継承
オブジェクト指向の代表的な特徴をあげると……
※全てのオブジェクト指向言語が これらの特徴を備えているわけではない
Perl でオブジェクト指向
Perl でオブジェクト指向
package Classname;use strict;use warnings;
sub new { my ($class) = @_; return bless { field => $field, }, $class;}
Perl でオブジェクト指向
• カプセル化されていない• public/privateなど可視性を指定できない• オブジェクト=パッケージという縛り
オブジェクト指向のように書けるが……
という短所(見方によっては長所?)もある
Perl 6
Camelia
Perl 6 について
• 既存の Perl (~ v.5.18)とは異なる言語• 互換性がない• 作者は Larry Wall ( Perl と作者が同じ)• オブジェクト指向スクリプト言語• 静的型付けにも対応• 全ての仕様を反映した実装はまだない
基本的な話
完全な実装がない?
• 今はまだない• 仕様のある程度の部分に対応した実装はある• 今回提示するコードは Rakudo で動作確認しました• テクニカルな実装をしなければ、けっこう使えるかも
Perl 6オブジェクト指向プログラミング
• 予約語• class• method• 同一ファイル内で定義も呼び出しもできる(良いかどうかは別として)
• sub も色々ある(ここで話すには時間がry)
クラス and メソッド
class Engineer { method greeting { say ‘hello, YAPC!’; }}
my $c = Engineer.new;$c.greeting; # hello, YAPC!
メソッドの可視性
メソッドの可視性class Engineer { method greeting { say ‘hello, YAPC!’; }
method !thinking { say ‘sleepy...’;}
my $c = Engineer.new;$c.greeting; # hello, YAPC!$c!thinking; # NG
メソッドの可視性
• メソッドに public/private を指定できる• private メソッドはメソッド名の最初に ! をつける• private メソッドはクラス外からはアクセスできないが当然クラス内からはアクセスできるので……
メソッドの可視性class Engineer { method greeting { say ‘hello, YAPC!’; }
method !thinking { say ‘sleepy...’;
method unconsciously { self!thinking;}
my $c = Engineer.new;$c.greeting; # hello, YAPC!$c!thinking; # NG$c.unconsciously; # sleepy...
アトリビュート
アトリビュートclass Attrs { has $!priv_var; has $.pub_var;
method print_all { say $!priv_var; say $.pub_var; } method set_all ($priv, $pub) { $!priv_var = $priv; $.pub_var = $pub; }}
my $attr = Attrs.new;$attr.set_all(1, 2);$attr.print_all; # 1 2
アトリビュート
• メソッドと同様に public/private を指定できる• さっきのコード、動きそうですが……
Cannot assign to a readonly variable or a value in method set_all at attrs.p6:10 in block at attrs.p6:16
エラー!
アトリビュート
• public アトリビュートはデフォルトでは readonly• 無理やり代入したい場合は ! を使う
アトリビュートclass Attrs { has $!priv_var; has $.pub_var;
method print_all { say $!priv_var; say $.pub_var; } method set_all ($priv, $pub) { $!priv_var = $priv; $!pub_var = $pub; # change twigil }}
my $attr = Attrs.new;$attr.set_all(1, 2);$attr.print_all; # 1 2
アトリビュート
• public アトリビュートはデフォルトでは readonly• 無理やり代入したい場合は ! を使う• ん……でも ! だと private 扱いになる?• じゃあクラス外からアクセスするには?
アトリビュート
class Attrs { has $!priv_var; has $.pub_var is rw;}
my $attr = Attrs.new;$attr!priv_var = “alpha”; # NG$attr.pub_var = “bravo”;
say $attr!priv_var; # NGsay $attr.pub_var; # bravo
アトリビュート
• public アトリビュートはデフォルトでは readonly• 無理やり代入したい場合は ! を使う• ん……でも ! だと private 扱いになる?• じゃあクラス外からアクセスするには?• is rw をつけることで writable にできる
継承
継承class Person { has $.name is rw;}
class Speaker is Person { method get_name { return $.name; }}
my $speaker = Speaker.new;$speaker.name = ‘risou’; # risou
my Person $p = Speaker.new;
継承
• 他の多くのオブジェクト指向言語と同様にメソッドは自分→親→……→ルートの順で探索する
• 親クラスのアトリビュート、メソッドを引き継ぐ• 多重継承もできるclass Charlie is Alpha is Bravo ... {
オーバーライド
オーバーライドclass Parent { method print_generation { say ‘first generation’; }}
class Child is Parent { method print_generation { say ‘second generation’; }}
Parent.print_generation; # first generationChild.print_generation; # second generationmy Parent $p = Child.new;$p.print_generation; # second generation
オーバーライド
• もちろんオーバーライドもできる• (ここ特筆すべきことないですね)
コンストラクタ
コンストラクタclass OneAttr { has $.attr;
method new ($attr) { return self.bless(*, :attr); }
method print_attr { say $.attr; }}
my $oa = OneAttr.new(10);$oa.print_attr; # 10
コンストラクタ
• コンストラクタの戻り値は bless• オブジェクトを生成するためにbless の第1引数に * をセットする
• bless の引数で名前付き引数を用いることでアトリビュートに値をセットできる
コンストラクタ
• ルートオブジェクトがコンストラクタを持つため引数付きコンストラクタが必要ないなら定義は不要
method new { return self.bless(*); }
コンストラクタclass OneAttr { has $.attr;
method new ($attr) { return self.bless(*, :attr); }
method print_attr { say $.attr; }}
my $oa = OneAttr.new;$oa.print_attr; # ??
Not enough positional parameters passed; got 1 but expected 2 in method new at con2.p6:4 in block at con2.p6:13
エラー!
コンストラクタ• 引数なしコンストラクタが呼べ……ない!• 同名のメソッドが既に定義されているため(引数の有無/数にかかわらず同名のメソッド扱い)
• これは不便ですね• デフォルトの引数なしコンストラクタと独自定義の引数ありコンストラクタを共存させたい
• させましょう!
コンストラクタ• 引数なしコンストラクタが呼べ……ない!• 同名のメソッドが既に定義されているため(引数の有無/数にかかわらず同名のメソッド扱い)
• これは不便ですね• デフォルトの引数なしコンストラクタと独自定義の引数ありコンストラクタを共存させたい
• させましょう!
コンストラクタ• 引数なしコンストラクタが呼べ……ない!• 同名のメソッドが既に定義されているため(引数の有無/数にかかわらず同名のメソッド扱い)
• これは不便ですね• デフォルトの引数なしコンストラクタと独自定義の引数ありコンストラクタを共存させたい
• させましょう!
コンストラクタ• 引数なしコンストラクタが呼べ……ない!• 同名のメソッドが既に定義されているため(引数の有無/数にかかわらず同名のメソッド扱い)
• これは不便ですね• デフォルトの引数なしコンストラクタと独自定義の引数ありコンストラクタを共存させたい
• させましょう!
コンストラクタclass OneAttr { has $.attr;
multi method new ($attr) { return self.bless(*, :attr); }
method print_attr { say $.attr; }}
my $oa = OneAttr.new;$oa.print_attr; # Any()
コンストラクタ
• multi これだけ!• multi をつけることでメソッドをオーバーロードできる• (親クラスの)引数なしメソッドと引数ありメソッドが同じクラスの中で同居できる
Role
Rolerole Dice { method roll { return [1..$.plane].pick; }}
class Cube does Dice { has $.plane = 6; }
my $dice = Cube.new;$dice.roll; # 1~6
Role
• オブジェクトに役割を与える(Javaで言うとインタフェース)
• 継承とは異なるものなので注意• オブジェクト生成時に Role を与えることもできる
Rolerole Dice { method roll { return [1..$.plane].pick; }}
class Cube { has $.plane = 6; }
my $dice = Cube.new does Dice;$dice.roll; # 1~6
と、ここまで駆け足でお送りしてきました
Perl 6
• Perl よりも自然にオブジェクト指向が書ける• 記号プレフィックス(sigil, twigil)が豊富・複雑に• (ここでは紹介してないけど)メタクラスなどもあります
ところで
• Perlでオブジェクト指向するならモジュール使いましょう• 個人的には素で書くのも嫌いじゃないけど、規模が大きくなると苦しくなってくる
OOP モジュール
• 選択肢はいくつかある• Mouse• Moo• より良い選択肢(の候補)• p5-mop-redux
OOP モジュール
• 選択肢はいくつかある• Mouse• Moo• より良い選択肢(の候補)• p5-mop-redux
p5-mop-redux
• 今日説明した Perl 6 の OOP にかなり近い• ドット演算子は無理だけと twigil はなんとかできそう• コアに入れば Perl での OOP がすごく楽になるはず