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

I have a hash that I would like to get the values for by using subroutine names. Example,
# Hash Value $hash{'name'} = 'Herk'; $self->get_name(); # Returns 'Herk'
Can someone help me fill in the blank about how I should do this?

Update

Let me state what I am avoiding trying to do. I don't want to have to create methods for every key in my hash. If I have a 100 keys I COULD write 100 get methods and 100 set methods but that is alot of work.

What I was hoping for was for one or two methods that evaluates a 'get_' or 'set_' calls, intercepts it and does an operation with my hash based upon the method name. That way all I have to worry about is making sure all my fields are in the hash.

Sorry, I was unclear in explaining what I wanted.

Replies are listed 'Best First'.
Re: Link methods to hash values
by shmem (Chancellor) on Oct 01, 2006 at 21:36 UTC
    Why just for %hash? why not also for %nifty_hash? Oh, and you might not want this behaviour for %normal_hash.

    Solution: make your hashes objects of a class that implements that behaviour. Ah, you are already on that path. I see $self in your code. But how are %hash and $self supposed to be related?

    package myHash; sub new { bless {}, shift } sub AUTOLOAD { # next two lines just to see what's happening... print '@_ = ('.join(', ',map{"'$_'"}@_), ")\n"; print "\$AUTOLOAD = $AUTOLOAD\n"; my ($self,$value) = @_; (my $key = $AUTOLOAD) =~ s/.*:://; $self->{$key} = $value if $value; $self->{$key}; } 1;

    Now you can

    #!/usr/bin/perl use myHash; $thingy = myHash->new(foo => 'bar'); print $thingy->foo,"\n"; print $thingy->foo('baz'),"\n"; print $thingy->age('ageless'),"\n"; __END__ #output: @_ = ('myHash=HASH(0x8166c28)') $AUTOLOAD = myHash::foo @_ = ('myHash=HASH(0x8166c28)', 'baz') $AUTOLOAD = myHash::foo baz @_ = ('myHash=HASH(0x8166c28)', 'ageless') $AUTOLOAD = myHash::age ageless @_ = ('myHash=HASH(0x8166c28)') $AUTOLOAD = myHash::DESTROY

    Note the last two lines - since our myHash package doesn't have a method called DESTROY, the AUTOLOAD routine is called to handle DESTROY during global destruction (at program's end). See perlobj.

    But you don't have to roll your own, There are some modules at CPAN which implement autogeneration of accessors, getters/setters (for instance, Class::Accessor, Class::MethodMaker, ...), then there's Spiffy which provides some other nifty features.

    --shmem

    _($_=" "x(1<<5)."?\n".q·/)Oo.  G°\        /
                                  /\_¯/(q    /
    ----------------------------  \__(m.====·.(_("always off the crowd"))."·
    ");sub _{s./.($e="'Itrs `mnsgdq Gdbj O`qkdq")=~y/"-y/#-z/;$e.e && print}
Re: Link methods to hash values
by Hue-Bond (Priest) on Oct 01, 2006 at 18:12 UTC

    As I understand it, doing it by hand would be something like:

    my %hash; sub get_name { my $subname = (caller 0)[3]; $subname =~ s/.*::get_//; print $hash{$subname}, "\n"; } $hash{'name'} = 'Herk'; get_name;

    But I believe the best way would be to resort to some CPAN module. I haven't done much OO programming but I think Class::Accessor will fit.

    Update: Changed v10 to "\n". I always use v10 in quick tests because it's easier to type.

    --
    David Serrano

Re: Link methods to hash values
by GrandFather (Saint) on Oct 01, 2006 at 19:03 UTC

    Why not simply provide a 'get' method?

    $self->get ('name'); ... sub get { my ($self, $param) = @_; return undef if ! exists $self->{$param}; return $self->{$param}; }

    Alternatively there are CPAN modules such as Class::MethodMaker that will generate getters and setters for you given a list of properties.


    DWIM is Perl's answer to Gödel
         return undef if ! exists $self->{$param};

      That's more correct (and, in my opinion, readable) as:

         return unless exists $self->{$param};

      Beware of undef in list context.

      I just wanted to use a more explicit method name rather than pass a value all the time. I figured it, cannot be that hard right?

      Let me take a look at Class:MethodMaker and see if that gives me what I want...

      Thanks!

        If you don't want to use something like Class::MethodMaker, it's pretty trivial to do this sort of thing yourself.

        package Foo; use strict; use warnings; foreach my $name(qw(foo bar baz quux narf)) { no strict 'refs'; *{ 'Foo::get_' . $name } = sub { my $self = shift; return $self->{$name}; }; }

        Constructing the equivelent set_* methods is left as an exercise for the reader. :)

Re: Link methods to hash values
by lyklev (Pilgrim) on Oct 01, 2006 at 19:06 UTC

    You should probably ask yourself whether this is really the way you want to go. First of all, you don't feel like defining one hundred methods for one hundred hash keys. But say you find a way, you still have at least one hundred different calls, so are you ok with that? It will be very difficult to let your program grow.

    Why don't you try to understand 'objects' (that is, blessed references) first, define a getter, a setter and making the key as one of the arguments. The getter and setter methods can validate the input for you.

    If you really insist and if you are prepared to follow the narrow, steep, winding path you could use a method called AUTOLOAD; this method will be called in case the requested method can not be found. It allows you to examine the method that was called, so you can extract the desired key from the method. In fact, the O'Reilly book "Perl Objects, References and Modules", chapter 11 (or its successor "Intermediate Perl") describes how to do just what you want.

Re: Link methods to hash values
by GrandFather (Saint) on Oct 01, 2006 at 18:15 UTC

    Now ask the real question (see XY Problem).

    It looks like you want to return the 'name' property of an object. Assuming that $hash is the object that was blessed to create the object instance then the following is probably what you want:

    sub get_name { my $self = shift; return $self->{name}; }

    DWIM is Perl's answer to Gödel
Re: Link methods to hash values
by jeteve (Pilgrim) on Oct 02, 2006 at 14:53 UTC
    Did you try Class::AutoAccess?

    It automatically implements those methods for you, and as soon as they are real methods after the first call, it doesn't affect your program performance

    -- Nice photos of naked perl sources here !