Search code examples
perlfunctormoose

Using Moose in Perl to implement a functor


I'm working with some code in Perl that wants me to pass a method to it. But, I'd like to keep some state about what happens in the method. I know I can use a global variable for this, but I'd prefer something a little cleaner/object oriented. Is there a way to use Moose to create a functor/function object?


Solution

  • You just need a closure.

    sub make_closure {
       my ($name) = @_;
       my @greets = ('Good morning', 'Good afternoon', 'Good evening', 'Good night');
       my $next = 0;
       return sub { "$greets[ $next++ % @greets ], $name" };
    }
    
    my $joe  = make_closure("Joe");
    my $jane = make_closure("Jane");
    
    say $joe->();  # Good morning, Joe
    say $joe->();  # Good afternoon, Joe
    say $jane->(); # Good morning, Jane
    say $jane->(); # Good afternoon, Jane
    say $jane->(); # Good evening, Jane
    say $joe->();  # Good evening, Joe
    

    The other way would be to make an object that overloads &{}.

    use Moose;
    
    use overload '&{}' => \&call;
    
    has code   => ( is => 'rw' );
    has called => ( is => 'rw', default => 0 );
    
    sub call {
       my ($self) = @_;
       $self->called( $self->called() + 1 );
       return $self->code;
    }
    

    my $o = __PACKAGE__->new(code => sub { say "called!" });
    $o->();          # called!
    $o->();          # called!
    say $o->called;  # 2