Beefy Boxes and Bandwidth Generously Provided by pair Networks
go ahead... be a heretic
 
PerlMonks  

Reference as a hash key

by Anonymous Monk
on Aug 25, 2009 at 15:48 UTC ( #791114=perlquestion: print w/ replies, xml ) Need Help??
Anonymous Monk has asked for the wisdom of the Perl Monks concerning the following question:

Given that this works:

my $ref = []; my %hash; $hash{$ref} = 1; print keys %hash;

and returns "ARRAY(0x.....)", my question is; is this likely to bring about some tutting and shaking of heads in experienced perl developers?

(Some background: I needed a method of storing which anonymous arrays out of a large number had been examined, and quickly checking that store to see if one had already been examined.)

Comment on Reference as a hash key
Download Code
Re: Reference as a hash key
by goeb (Pilgrim) on Aug 25, 2009 at 16:01 UTC
    I don't really know about using the reference as a hash key, someone else will have to answer this question. There is however Scalar::Util refaddr function which you could use to explicitely use the reference's address as a key to a hash (or even as an array index). Edit: Better use hashes for this, performance with an array might be much worse since the memory addresses can get very huge.
Re: Reference as a hash key
by ssandv (Hermit) on Aug 25, 2009 at 16:04 UTC

    Well, your use case probably isn't as clearly stated as you think it is. If you're saying that you need to quickly check to see if a given anonymous array has been examined, why not reserve the zeroth element of each array for a "I've been examined!" indicator?

    If, on the other hand, you mean that you need to check the entire set of arrays to see which ones have been examined, then you're still going to traverse the whole set of arrays, and a hash doesn't save you, because the long time isn't in the lookup, it's in the traversal.

Re: Reference as a hash key
by AnomalousMonk (Abbot) on Aug 25, 2009 at 16:05 UTC
    It depends on just what you want to do with the keys of your hash.

    As you see, all hash keys are stringified, so the keys can never again be used as references (the original references are unaffected). However, they are stringified uniquely because each reference has a unique address, so I see no problem with using the string representation to flag that a particular array has been handled.

    Of course, if the referent of a reference is destroyed, the hash key corresponding to it is unaffected! You have to take care of this on your own. And remember: if references are destroyed and new ones created, old reference addresses may be re-used!

    Actually, I think I would tend to use something like bluestar's suggestion in Re: Reference as a hash key: it's more general and flexible, probably more maintainable.

    Updates:

    1. Added note about reference destruction.
    2. Added endorsement of bluestar's suggestion.
Re: Reference as a hash key
by bluestar (Novice) on Aug 25, 2009 at 16:15 UTC
    Why not rather have a data structure like this:
    $array_ref = [ { array_ref => $ref, has_been_examined => 1, }, { array_ref => $ref, has_been_examined => 1, }, etc ... ]
    By doing this you are able to associate additional custom metadata to each anonymous array.
Re: Reference as a hash key
by LanX (Canon) on Aug 25, 2009 at 16:43 UTC
    As long as no anonymous arrays are destroyed and defined during your examination there shouldn't be a risk of collisions of equally stringified refs.

    I assume you know that the stringification of a reference is a one-way-function ... if you ever need to know the corresponding ref you should consider, writing  $hash{$ref} = $ref; instead.

    (or using something like Tie::RefHash)

    Cheers Rolf

      hmm just a (maybe not too) strange thought ...

      ... if these are just plain arr-refs and not already blessed obj-refs you might use a simple hack to flag them with attributes :

      You may bless them into a package _SEEN_ and check it with ref ! 8)

      DB<1> $arr=[] DB<2> bless $arr,"_SEEN_" DB<3> p ref $arr _SEEN_ DB<4> bless $arr,"_UNSEEN_" DB<5> p ref $arr _UNSEEN_

      You wont have any collision risk and you can safely pass the refs around with the information attached without caring about any extra %seen hash.

      Cheers Rolf

      UPDATE: I just noticed that (unfortunately) there is no way to "unbless" references in perl afterwards! :-(

      You may write bless $arr,"ARRAY" to try undoing blessing but even if ref now returns "ARRAY" it's NOT the same as "unblessing" and may cause subtle bugs ... just check it with Scalar::Util::blessed $arr ! Pity!

Reaped: Re: Reference as a hash key
by NodeReaper (Curate) on Aug 25, 2009 at 16:44 UTC
Re: Reference as a hash key
by Sewi (Friar) on Aug 25, 2009 at 17:39 UTC
    Each reference is unique, so it's a valid key. I don't know any reason why your solution shouldn't work, I also did something like this some time ago and it worked. I can't see any reason why you shouldn't use a ref as a key, but always remember that tie'ing the whole thing won't work.

Log In?
Username:
Password:

What's my password?
Create A New User
Node Status?
node history
Node Type: perlquestion [id://791114]
Approved by AnomalousMonk
help
Chatterbox?
and the web crawler heard nothing...

How do I use this? | Other CB clients
Other Users?
Others rifling through the Monastery: (8)
As of 2014-12-26 09:57 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    Is guessing a good strategy for surviving in the IT business?





    Results (171 votes), past polls