Comparing a reference?

T

Tim McDaniel

I inherited code that had, in effect,

my $kind = 'Val';
...
if ($kind eq 'Val')

For various reasons, I want to change it to

my $kind = \&some_sub;

Is there a reliable, guaranteed way to do that and still have the
conditional? (This is in 5.8.8 and I have no way to change that.)

man perlref says

Using a string or number as a reference produces a symbolic
reference, as explained above. Using a reference as a number
produces an integer representing its storage location in memory.
The only useful thing to be done with this is to compare two
references numerically to see whether they refer to the same
location.

if ($ref1 == $ref2) { # cheap numeric compare of references
print "refs 1 and 2 refer to the same thing\n";
}

I also ran across
http://stackoverflow.com/questions/4064001/how-should-i-compare-perl-references
, where there was one reply that said

The function you are looking for is refaddr from Scalar::Util
(after ensuring that the values being compared really are
references):

use Scalar::Util 'refaddr';

if ($obj1 and ref($obj1) and $obj2 and ref($obj2) and
refaddr($obj1) == refaddr($obj2))
{
# objects are the same...
}

with tchrist replying "The extraordinary measures taken by
cpan/List-Util/lib/Scalar/Util/PP.pm's refaddr() function to divine
the referent's real address are exceeded only by the blessed()
function's measures to find the package name.", and a reply to that
that it's in the Perl core and compiled, so it's cheap.

Is there a reason to use SCalar::Util::refaddr instead of ==?
 
T

Tim McDaniel

Quoth (e-mail address removed):

The only reason is if there is a chance either ref might point to an
object which overloads either == or numify, or if there is a chance
$kind might not hold a ref at all. If you know you are dealing with
unblessed refs there is no reason not to use ==.

If there is a chance you might be running under ithreads, it's important
to check against the current value of \&some_sub, rather than trying to
cache the numeric value, since the value of the ref will change when a
new thread is forked.

Thank you for the quick response.

$kind is one reference out of four possible refs, along the lines of

my $lookup = {
CASE1 => \&Pkg::Sub1,
CASE2 => \&Pkg::Sub2,
CASE3 => \&Pkg::Sub3,
CASE4 => \&Pkg::Sub4,
};
$kind = $lookup->{$arg};
return unless $kind;

There is no threading, no blessing, and no object munging in the 40
lines between setting and this comparison.

Reading in further Google hits, though, I think I may do refaddr just
to be paranoid.
 
T

Tim McDaniel

$kind is one reference out of four possible refs, along the lines of

my $lookup = {
CASE1 => \&Pkg::Sub1,
CASE2 => \&Pkg::Sub2,
CASE3 => \&Pkg::Sub3,
CASE4 => \&Pkg::Sub4,
};
$kind = $lookup->{$arg};
return unless $kind;

There is no threading, no blessing, and no object munging in the 40
lines between setting and this comparison.

Reading in further Google hits, though, I think I may do refaddr just
to be paranoid.

I just realized that $arg is also in scope at the point of the
comparison. So instead of doing

if (Scalar::Util::refaddr($kind) == Scalar::Util::refaddr(\&Pkg::Sub1)) {

I can simply do

if ($arg eq 'CASE1') {

and finesse away the whole issue.

Still, thank you for the answer.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,754
Messages
2,569,527
Members
44,999
Latest member
MakersCBDGummiesReview

Latest Threads

Top