7578


perlで例外処理をするモジュールとしてTry::Tinyがあります。

使うときは以下のように定義しますが、これが文法的にどうやって実装されているか確かめたくてモジュールを読んでみましたが、分かりませんでした。

Javaと同じような文法ですが、perlにはtry構文は用意されていません。  
Try::Tinyがどうやってこの文法を実装しているの知りたいです。

> perldoc Try::Tiny
[code]

             try {
               die_sometimes();
             } catch {
               # ...code run in case of error
             } finally {
               if (@_) {
                 print "The try block died with: @_\n";
               } else {
                 print "The try block ran without error.\n";
               }
             };
    
[/code]

以下、モジュールを使わず定義だけしてみて、B::Deparseで構文解析して内部でどう処理されているか確認しましたが、解析結果を見てもよく分かりませんでした。

perl -v: 5.16.2  
osx: 10.9.5

[code]

    $cat ./h.pl 
    #!/usr/bin/perl
    use strict;
    use warnings;
    
    try {
            print "try\n";
    } catch {
            print "catch\n";
    };
    
    $perl -MO=Deparse ./h.pl 
    use warnings;
    use strict;
    try {
        print "try\n"
    } (catch {
        print "catch\n"
    } );
    ./h.pl syntax OK
    
[/code]

try()の引数にコードブロックとリストを渡しているのかな？と推察していますが、詳しく分かる方がいらっしゃたら教えてください。

よろしくお願いします。


CC BY-SA 3.0
2015-03-06T10:53:13.103
7549
2015-03-07T06:59:45.673
2015-03-06T11:00:42.827
8695
8695
question
perl
Try::Tinyモジュールの実装方法


Try/Tiny.pmのsub try (&;@) {...}を直接読むしかないかと思います。  
<http://cpansearch.perl.org/src/DOY/Try-Tiny-0.22/lib/Try/Tiny.pm>

evalでチェックして、catchしたら$catch->($error)を返してるような感じですね。  
あと、モジュールの中身まで見ていきたい場合はperl -dで実行してみましょう。  
奥深くまで追いかけることができます。


CC BY-SA 3.0
2015-03-06T11:24:25.583
7552
2015-03-06T11:24:25.583
3709
7549
answer


お察しの通りです。（そのため最後に";"が必要になります）  
try/catch/finallyは構文に見せかけた単なるサブルーチン名です。

サブルーチンは引数にコードリファレンスを取る事ができるので以下のように呼ぶ事ができます。

[code]

    sub foo {
        my $code_ref = $_[0];
        return $code_ref->();
    }
    
    foo(sub { ... });
    
[/code]

すでに定義されているサブルーチンは括弧を省略できるので次のようにも書けます。

[code]

    foo sub { ... };
    
[/code]

さらにサブルーチンプロトタイプで第一引数の基本型を指定しておけば、fooに続く部分がブロックでもハッシュリファレンスでもなく、コードリファレンスであることをperlコンパイラに明示できるので、"sub"を省略できます。

[code]

    sub foo (&) {
        my $code_ref = $_[0];
        return $code_ref->();
    }
    
    foo { ... };
    
[/code]

プロトタイプでコードリファレンスを指定する場合、第一引数にしか適用できないため同じようなプロトタイプを使ったサブルーチンを入れ子にします。

[code]

    sub foo (&;@) {
        my ($code_ref, @rest) = @_;
        return $code_ref->(@rest);
    }
    
    sub bar (&) {
        my $code_ref = $_[0];
        return $code_ref->();
    }
    
    foo { ... } bar { ... };
    
[/code]

`bar`がまず処理され、その結果が`foo`の引数`@rest`になります。


CC BY-SA 3.0
2015-03-07T06:59:45.673
7578
2015-03-07T06:59:45.673
62
7549
answer