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

I feel like this is a very simple question, but I can't seem to find the answer.

I'm trying to create a new class. Most of my accessors are dynamically generated with AUTOLOAD, but I have a few that need to verify data instead of blindly accepting it. Take this code as example:

sub new { my $class = shift; my %args = @_; my %hash = ( _foo => 0, _bar => 0, _baz => 0, ); my $self = bless( \%hash, $class ); ... return $self; } sub AUTOLOAD { # do stuff to auto-generate accessors for anything in my %hash + (except without preceding underscore), so "foo" and "bar" } sub baz { # actually verify input data here }

Now, where my "..." is in the new method, I was doing something like this:

foreach ( keys %args ) { if( exists $hash{ '_' . $_ } ) { $self->{ $_ } = $args{ $_ }; } }

So if I called my new as This::Object->new( bar=>7, baz=>9 );, this would just put each value into my object. But, obviously, I want to actually verify this data, so what I really want to do is call the appropriate accessor method, but I can't seem to figure out how. So, in this example, the 'new' method would do something like call $self->bar( 7 ) and $self->baz( 9 )

Can somebody please point me to the appropriate documentation for this? It almost certainly has to be very common-place in class creation. Thanks in advance for the help!

    -Bryan

Replies are listed 'Best First'.
Re: Calling arbitrary method from new
by chromatic (Archbishop) on Jun 10, 2005 at 03:32 UTC

    Are you looking for something like:

    for my $argument ( keys %args ) { $self->$argument( $args{ $argument } ) if exists $hash{ '_' . $argument }; }

    As a side note, I prefer to generate accessors at compile-time without using AUTOLOAD when possible. Unless you predeclare all of the methods you're generating with subs or provide your own can(), you've made life more difficult for users of your code.

      Yes, I believe that is exactly what I want. I was trying to do something like $self->&{ $argument }( ... ), so I can't believe I didn't try this.

      On the other note: Is it really better to declare all of my methods, even if they are all so similar? I was reading through one of the intro to OO articles in the perldocs, which said AUTOLOAD is good, but I can see your point. Maybe I'll have to rewrite some of my code then.

      Thanks for the help!

          -Bryan

        No ampersand, but the way chromatic wrote it:

        $self->$argument( ... )
        Recently there was an interesting discussion on the use of AUTOLOAD for accessor generation; it starts here. In particular, tilly's first reply illustrates the approach that chromatic alluded to.

        the lowliest monk

        If I have a number of very similar methods, I like to highlight that by generating them in a loop with something like:

        for my $method (qw/ foo bar /) { no strict 'refs'; *$method = sub { use strict 'refs'; my $self = shift; $self->{"_$method"} = shift if @_; return $self->{"_$method"}; } }

        I'd usually use AUTOLOAD for this only if the list is infinite - for example if attribute methods are created on demand for arbitrary attributes supplied for the user.

        Hugo