Perl for Perl Mongers (YAPCに来た人は皆Perl Mongerでは?)
TIME rest time current/total
TopicsPlaceHolder

Perl for Perl Mongers (YAPCに来た人は皆Perl Mongerでは?)

YAPC::Asia Tokyo 2014

Aug 30th, 2014

Attention

別枠でやっているトークが非常に面白そうですが、途中で抜けられると悲しみ。(僕も行きたい)

ベストスピーカーの投票だけは何卒…

ちなみにトークの最後に驚きの発表が…?

Profile

songmu

昨日のライブコーディングのお詫び

Recent Output

neet

経歴

いろいろな仕事・いろいろな技術を使ってきたけど、Webの仕事をしたかったのとPerlが書きたくてカヤックに転職(2011年)。
それからPerlをたくさん書くように。

cron好き(?)

WEB+DB PRESS: cron周りのベストプラクティス

中国人疑惑

私とPerl

My CPAN Modules

無駄にCPANモジュールを上げていることで有名

http://acme.cpanauthors.org/for/japanese 調べ

6番目!

recent distでsortすると

2番目!

何故Perlを使いたいと思ったか

注意

Bradfitz said

I love and hate all languages.
~ Go Conference 2014 spring

I love (and hate?) Perl

言語には良し悪しがあるし、Perlには古臭い部分があるのも事実だろう。

でも、自分よりはるかに総合力の高いエンジニアの中にPerlを好んで使う人がいるという 事実から学ぶべきところもあると考えた方が良いのではないだろうか。

PerlをdisりたいならPerlを学んでから来てください。(Uzullaさんインスパイア)

Agenda

Perlの好きなところ

変数宣言


if (my $prop = $obj->prop) {
    ...
}

ところでgolangだとこう書けるの良い

if prop := obj.Prop(); prop != nil {
    ...
}

subが3文字

sub sub_name {
    my ($arg1, $arg2) = @_;
    # <- ここが揃うのが好き(但し4スペに限る)
}

オブジェクト指向

コンストラクタ

package Class::Name; # クラスを定義(名前空間がクラスになる)
sub new {
    my ($class, %args) = @_; # 第一引数はクラス名(Class::Name)
    my $obj  = bless {%args}, $class;
    return $obj;
}
# my $obj = Class::Name->new(%args); とか呼び出す

blessを使って、単なるデータ構造(この場合ハッシュ)をオブジェクトに昇格させる。
(僕は昔JavaとかやってたけどPerlでオブジェクト指向がわかった(かも))

メソッド/アクセサ

sub prop {
    my $self = shift;     # 第一引数からオブジェクトを取り出す
    return $self->{prop}; # ハッシュrefのフィールドから読み出す
}
# `$obj->prop()` でアクセス `$obj->prop` と()を省略可能

アクセサ(セッタも兼ねる例)

sub prop {
    my $self = shift;            # 第一引数からオブジェクトを取り出す
    $self->{prop} = shift if @_; # 引数が残っていたら値をセット
    return $self->{prop};
}
# `$obj->prop()` でアクセス `$obj->prop` と()を省略可能
# `$obj->prop(10)` で値をセット

あくまでも実装の一例

アクセサは全てメソッド

MouseとかMooとかClass::Accessor::Liteとかって何?

基本的には素のオブジェクト指向を別の書き方で実現できるようにしているだけ。

GCとか変数のスコープとか

リファレンスカウントによるメモリ管理

ブロックスコープ


my $hoge = 'hoge';
{
    my $obj = Hoge::Fuga->new;
    say $hoge; # hoge
}
# $objはここでは参照不可能

CoWフレンドリー

ガードオブジェクト

ガードオブジェクト

  1. スコープを抜ける
  2. リファレンスカウントが0になる
  3. オブジェクトが確実に即座に破棄される
  4. その前にオブジェクトのデストラクタが呼ばれる

ということを利用したテクニック。終了処理を確実にやりたいときなどに重宝する。

デストラクタを利用しているので、循環参照に注意。シグナルにも注意が必要。

Scope::Guard

use Scope::Guard;
{
    my $guard = Scope::Guard->new(sub {
        say 'ya!';
    });
    say 'say'
} # say\n ya! の順に出力される

# 以下のシンタックスシュガーも提供されている
{
    my $guard = scope_guard {
        say 'ya';
    }
}

スコープを抜けた時に確実に実行させたい処理を記述しておく。golangで言うところのdefer

Test::Mock::Guard

use Test::Mock::Guard;
{
    my $guard = Test::Mock::Guard->new('ClassName', {
        method1 => sub {
            ...
        },
    })
}

スコープの中でクラスの挙動を差し替える。スコープを抜けると元に戻る

Test::mysqld

use Test::mysqld;
my $mysqld = Test::mysqld->new(my_cnf => {'skip-networking' => ''});
my $dbh = DBI->connect($mysqld->dsn);

テスト用にサラのmysqldを起動する。$mysqldはガードオブジェクトにもなっていて、オブジェクトが破棄されるときにちゃんとMySQLのプロセスを落とすようになっている。

Proc::Guardっていう汎用的な別モジュールも。

Test::mysqld大好き。

ダイナミックスコープの活用

localでグローバル変数を一時的に書き換える

ファイル一気読みの例

my $content = do {
    local $/;
    open my $fh, '<:encoding(UTF-8)', 'filename' or die $!;
    <$fh>
};

# この例は以下で良い :p
use Path::Tiny
my $content = path('filename')->slurp_utf8;

ダイナミックスコープの活用例

ref. 複雑なデータ構造の中にうまっているデータのパスをさがす方法

再帰的に呼び出しをする場合にダイナミックスコープを活用することによってスッキリ書くことができる。(静的スコープしか活用できない言語の場合は、引数で頑張って引き回す形になる)

オブジェクトの値を一時的に差し替える

Tengの例。

sub get_userhash_by_id {
    my ($teng, $id) = @_;
    # row objectを作成をスコープ内で抑制
    local $teng->{suppress_row_objects} = 1;
    return $teng->single(user => {id => $id});
}

ガードオブジェクトパターンを使ったTeng::Plugin::RowObjectCreationSwitcherもある。

ref. Teng::Plugin::RowObjectCreationSwitcherが便利な件

DSL

DSLの実現

Subroutine prototypes

sub hoge($) {
    my $scalar = shift;
}

sub run(&) {
    my $sub = shift;
    $sub->();
}

sub CONST() { 'CONST' } # 定数 (定数扱いにならないこともある)

sub名の後にparenを付けて引数の型を指定することができる機能だが、今はほとんど使われない。DSLを作るときに活用されるという本来の目的とはちょっと違う用途に使われることがある。

cpanfileの場合

requires 'Plack::Request';
on test => sub {
    requires 'Test::More';
};

Daikuの場合

namespace db => sub {
    desc 'データベースをmigrateします';
    task migrate => sub {
        sh 'tools/db/migrate';
    };
};

desc 'テスト回します';
task test => sub {
    my ($task, @args) = @_;
    sh qw(prove -lr), @args;
};

desc 'CPANモジュールをインストールします';
task install => sub {
    my ($task, @args) = @_;
    sh qw(cpanm --quiet --with-develop --notest --installdeps .), @args;
};

DBIx::Schema::DSLの場合

create_table book => columns {
    integer 'id',   primary_key, auto_increment;
    varchar 'name', null;
    integer 'author_id', not_null;
    decimal 'price', 'size' => [4,2];

    add_index  'author_id_idx' => ['author_id'];
    belongs_to 'author';
};

Perlは記号が多いとは何だったのか。(多いこともありますね…)

リストの扱いについて

リストと配列の違い

リストコンテキストとスカラーコンテキスト

リストがフラットだから実現できること

委譲が簡単

Perlではサブルーチン(含メソッド)の引数は、@_にフラットに格納されているので委譲が簡単に書ける。

sub method {
    my ($self, @args) = @_;
    $self->obj->method(@args);
}

# 以下も同じ
sub method {
    shift->obj->method(@_); # shift は shift(@_) と同じ
}

javascriptだとapplyとかを使う。

ClassB.prototype = {
    obj: new ClassA(),
    method: function() {
        this.obj.method.apply(this, arguments);
    }
};

mapやgrep, split等でリスト処理して変換して行くのが楽しい

use List::MoreUtils qw/uniq/;
say for uniq sort map {
    split /-/, $_ # splitで分割された複数の結果がフラットに返される
} qw/1-2-44-58 3-33-15-1/;

逆順に考えないといけないのでそこは分りづらい。

Rubyだとこういうふうに順番に書ける。flattenが必要になる(と思う)。

%w(1-2-44-58 3-33-15-1).map {|v| v.split(/-/)}.flatten.sort.uniq.each{|v| puts v}

誤解について

Perlは記号が多い・読みづらい

よくある無知な人の思考停止テンプレdisなので、どうでもいいんですが、

Sigil($hogeの$)があるから、記号が多いってのはちょっと違うと思っていて、変数にSigilがあるから、関数やメソッドの括弧を省略しても違和感がない部分があると思っていて、例えば、Rubyなんかだと、関数と変数の区別がつかず、優先順位の問題でこの場合は括弧が必要とかそういうのがある。

JavaScriptとかGolangみたいにメソッド呼び出しは括弧が必須で、括弧がない場合はFunction型が返るってのはいいなとか思います。関数呼び出しに括弧が必須だとDSLとかがちょっとかっこ悪くなっちゃうけど、括弧が必須ならsigilは無くても良いんだろうな、という感じはします。

デリファレンスとかその辺は、まあ、ぱっと見は汚く見えてしまうだろうなーとは思う。慣れの問題ではあるけど。

Perlは衰退している?

ネット上の情報が古いんだけど…

文化について

後方互換を大切にする文化

互換性を保つと「小さな」ツールを組み合わせやすくなる

小さいパーツを組み合わることのメリット

小さいパーツとCPANエコシステム

CPANのサイトデザイン

コミュニティの成熟

Perlと黒魔術

オワコン感について

ちなみにPerlおじさんがFA宣言した結果

Perl程長い間愛されている言語はなかなかない

結論

Perlは面白い

最後に

次の所属について

9月から株式会社はてなにジョインします

hatena

エンジニア(に限らず)絶賛採用中です

http://hatenacorp.jp/recruit/career/