めも:Sub::Future

継続を使わない場合のget_multiのまとめ方を検討している。
これから、〜〜するぞ!という状態のオブジェクト。つまり継続もどき。

sub hoge {
    my $self = shift
    my $cache = $self->get_cache;# この手前で処理を停止させたい
    if( defined $cache ){
        return $cache;
    }
    my $db = $self->get_from_rpc;# この手前で処理を停止させたい
    $self->set_cache($db);
    return $db;
}


こんなかんじのロジックを次のように組み替え。

sub hoge_future {
    my $self = shift;
    return future( $self,q<get_cache>,sub{
        my $cache = shift;
        if( defined $cache ){
            return $cache;
        }
        return future($self,q<get_from_rpc>,sub{
            my $db = shift;
            set_cache($db);
            return $db;
        });
    });
}

そうすると、

::is $self->hoge,$self->hoge_future->next->next;

二つが等価になる。
止めたいところでとめて、何をしようとしているのかわかるので、
それをあつめてget_multiしたりbulk_loadしたりできる。

my $memfuture = $self->hoge_future->next;
my ($mem,$key) = @{ $memfuture->binded };
my $r = Memcached->get($key);
$memfuture->next_with($r);
package Sub::Future;
use strict;
use warnings;
use Scalar::Util qw/blessed/;
use Data::Util qw/is_instance/;
use base qw/Class::Accessor::Fast Exporter/;

__PACKAGE__->mk_accessors(qw/function binded callback class_name method_name/);


our @EXPORT = qw//;
our @EXPORT_OK = qw/future/;

sub future {
    my $self     = shift;
    my $method   = shift;
    my $callback = pop;
    my @args     = @_;
    return Sub::Future->new(
        {   binded      => [ $self, @args ],
            class_name  => blessed $self ? ref $self : $self,
            method_name => $method,
            function    => $self->can($method),
            callback    => $callback
        }
    );
}

sub next {
    my ($self) = @_;
    my @binded = @{ $self->binded };
    my $func   = $self->function;
    return $self->next_with($func->(@binded));
}

sub next_with{
    my ($self,$result) = @_;
    return $self->callback->($result);
}

sub run{
    my ($class,$future) = @_;
    my $value = $future;
    while( is_instance( $value,$class) ){
        $value = $value->next;
    }
    return $value;
}

1;