gargle has asked for the wisdom of the Perl Monks concerning the following question:

Fellow Monks,

How does one go to extend a base class that's implemented by means of a closure?

I have a base class in which the constructor initializes three fields

the base class

# constructor sub new { my $class = shift; my $self = { NAME => undef, ADDRESS => undef, PHONE => undef, }; my $closure = sub { my $field = shift; if (@_) { $self->{$field} = shift; } return $self->{$field}; }; bless( $closure, $class ); return $closure; }

I'd like to extend this class and add two more fields:

the extended class

# constructor sub new { my $class = shift; my $self = { CELLULAR => undef, EMAIL => undef, }; my $closure = sub { my $field = shift; if (@_) { $self->{$field} = shift; } return $self->{$field}; }; bless( $closure, $class ); return $closure; }

How do I make the extended class call the constructor of the base class and make sure that the two new fields are added at the same time?

I searched but couldn't find any documentation about this, not on perl monks, not on google :(

--
if ( 1 ) { $postman->ring() for (1..2); }

Replies are listed 'Best First'.
Re: OO: extending a closure object
by diotalevi (Canon) on Feb 22, 2006 at 20:25 UTC

    Check to see if you're being asked to do something that you know how to do, if so, handle it. If not, let the object you wrapped handle it. I made a small modification: the $self hash reference didn't need to be a reference so I promoted it to a regular hash. Your closure closes over that just fine.

    That is, the basic technique is wrapping and delegation. That's it. There's no special magic involved because it's a closure or because %self is a hash or a hash reference. That's probably why you didn't find anything specifically about this, it's a general technique and not something that requires anything new of you.

    package YourExtension; use base 'TheOriginal'; sub new { my $class = shift; my $extended = $class->SUPER::new( @_ ); my %self = ( CELLULAR => undef, EMAIL => undef, ); my $closure = sub { my $field = shift; if ( exists $self{$field} ) { if ( @_ ) { $self{$field} = shift } return $self{$field}; } else { return $extended->$field( @_ ); } }; bless( $closure, $class ); return $closure; }

    ⠤⠤ ⠙⠊⠕⠞⠁⠇⠑⠧⠊

      I see one problem here;

      return $extended->$field( @_ );

      requires that my setters in the base class are called exactly as the field names. Otherwise it won't work :(

      p.e. in my base class I have a field ACCOUNT and a setter called setAccount. The constructor above will however call my base class as $extended->ACCOUNT instead of $extended->setAccount.

      --
      if ( 1 ) { $postman->ring() for (1..2); }
        I think that was supposed to be
        return $extended->($field, @_);

        Caution: Contents may have been coded under pressure.
Re: OO: extending a closure object
by Roy Johnson (Monsignor) on Feb 22, 2006 at 20:24 UTC
    Since your base class doesn't restrict how you access $self, you can just put the extension attributes into an instance of the base class:
    package Extended; sub new { my $class = shift; my $closure = Base->new; $closure->(CELLULAR => undef); $closure->(EMAIL => undef); bless $closure, $class; }
    Why are you using this design? I don't see any advantages to it over more traditional styles. I guess it takes care of generic accessors.

    Caution: Contents may have been coded under pressure.