Beefy Boxes and Bandwidth Generously Provided by pair Networks
No such thing as a small change
 
PerlMonks  

Can an anonymous sub in a hash value know its key?

by webengr (Pilgrim)
on Mar 17, 2005 at 06:04 UTC ( [id://440275]=perlquestion: print w/replies, xml ) Need Help??

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

Greetings Monks!

This may have been asked (and answered) before, but I didn't run across it in the search tool.

My question is this: Is there a way that an anonymous sub stored as a hash value can have access to its associated key?

I am imagining something that would satisfy,

$h{'abc'} = sub { # # some sort of magic currently unknown to me # }; my $val = 'abc'; if ( $val eq $h{$val} ) { print "that works!",$/ }

At the moment this is just a curiosity for me, but if there is a way to do this it might come in handy sometime. If there's one thing that Perl has taught me, it's that I shouldn't jump to conclusions about what isn't possible.

PCS
I was recently asked, "Does your program know when it isn't running?"

Replies are listed 'Best First'.
Re: Can an anonymous sub in a hash value know its key?
by Anonymous Monk on Mar 17, 2005 at 10:25 UTC
    My question is this: Is there a way that an anonymous sub stored as a hash value can have access to its associated key?
    Unlike what several others have said, you can. In the code below, the anonymous sub gets the key belonging to the value passed in as its first argument.
    #!/usr/bin/perl use strict; use warnings; package Cute; sub TIEHASH {bless {}, shift} sub STORE {my ($self, $key, $sub) = @_; $$self{$key} = sub {$sub->($key)}} sub FETCH {${$_[0]}{$_[1]}} package main; tie my %hash, 'Cute'; my $greeting = sub {print "Hello, $_[0]\n"}; $hash{world} = $greeting; $hash{earth} = $greeting; foreach my $key (qw /world earth/) { &{$hash{$key}}; } __END__ Hello, world Hello, earth

      I like the package name.

      I think the lesson to be learned from this is that, with tie, the counterintuitive can be made to work! :-)

      Very nice! That does exactly what I was thinking of. I only wish I had a prize to award!

      PCS
      I was recently asked, "Does your program know when it isn't running?"

Re: Can an anonymous sub in a hash value know its key?
by jdporter (Paladin) on Mar 17, 2005 at 06:42 UTC
    The question isn't much different from asking if a string which is a hash value can know which key of the hash it belongs to. The problem is that values can move around. What if a given value (string or sub) is the value for more than one key? The other factor that impacts how this could be done is: How are you creating the anonymous subs? If you have access to that code, then a solution might be as simple as making a lexical variable to hold the key value, which the anon sub then closes over. But again, this presumes you can programmatically prevent a value from being copied or moved to another (incorrect) key later.
    sub make_sub_for_given_key { my( $key ) = @_; # amongst other arguments return sub { # this sub "knows" what $key is, forever. print "Hi! I belong to key '$key'\n"; } } my $key = "Tuesday"; my %hash; $hash{ $key } = make_sub_for_given_key( $key ); # later on, ask each sub what key it belongs to: for $key ( keys %hash ) { $hash{$key}->(); }
Re: Can an anonymous sub in a hash value know its key?
by BrowserUk (Patriarch) on Mar 17, 2005 at 06:38 UTC

    Not really. What happens if you associate the same sub with two keys?

    my $code = sub { # # some sort of magic currently unknown to me # }; $h{'abc','xyz'} = ($code) x 2;

    The only way I can see is if you embed a self-referential closure to the coderef within the sub and then grep the hash looking for a key with that coderef as it's value.

    You could probably use someting in the B::* set of modules to walk the optree and locate yourself (you own coderef) from within the sub, but you're still back to searching the hash for keys with that as a value.


    Examine what is said, not who speaks -- Silence betokens consent -- Love the truth but pardon error.
    Lingua non convalesco, consenesco et abolesco.
    Rule 1 has a caveat! -- Who broke the cabal?
Re: Can an anonymous sub in a hash value know its key?
by brian_d_foy (Abbot) on Mar 17, 2005 at 08:53 UTC

    There are a couple of ways to do this, although I wouldn't recommend any of these for code that is actually supposed to do anything other than show up in some contest entry.

    1. Bless the anonymous sub into a package with the same name as the key. It still acts like an anonymous sub, but it has this extra package name. Use ref() to get the package name back.
    2. Enchant the code ref by blessing it into a package and overloading the stringification operator, sorta like I did in Re: Track the filename/line number of an anonymous coderef. That was just for giggles, so don't put that in any code that means anything to you.
    3. Create a reverse index and use the stringified value of the anonymous sub as the key. You can handle duplicate values by not allowing them or making the reverse index store multiple keys.
    --
    brian d foy <bdfoy@cpan.org>
Re: Can an anonymous sub in a hash value know its key?
by ikegami (Patriarch) on Mar 17, 2005 at 06:39 UTC
    You could use closures ({ my $key = 'abc'; $h{$key} = sub { ... $key ... }; }), but it won't updated if you move the sub to another key, and the whole idea reaks of bad design.
Re: Can an anonymous sub in a hash value know its key?
by NetWallah (Canon) on Mar 17, 2005 at 21:58 UTC
    You could achieve the desired effect by wrapping a sub around accessing the values of the hash:
    my $sr=sub{print shift() . qq(\n)}; # Subref for Hash my %h=(a=>$sr, b=>$sr); sub gh{ # Sub to access the hash value and call the sub.. my $p=shift; # Get the KEY requested # In real life, you would first check to see if it was a coderef.. &{$h{$p}}($p); # Call the anon sub, passing it the key # Returns the result of the call.. }; gh($_) for qw(a b b a); ### Prints a b b a

        ..."I don't know what the facts are but somebody's certainly going to sit down with him and find out what he knows that they may not know, and make sure he knows what they know that he may not know, and that's a good thing. I think it's a very constructive exchange," --Donald Rumsfeld

Log In?
Username:
Password:

What's my password?
Create A New User
Domain Nodelet?
Node Status?
node history
Node Type: perlquestion [id://440275]
Approved by data64
Front-paged by holli
help
Chatterbox?
and the web crawler heard nothing...

How do I use this?Last hourOther CB clients
Other Users?
Others contemplating the Monastery: (5)
As of 2024-04-25 23:59 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found