Comparing a reference?

Do you have a question? Post it now! No Registration Necessary.  Now with pictures!

Threaded View
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

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

I also ran across
, 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

    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/'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 ==?

Tim McDaniel,

Re: Comparing a reference?

Quoted text here. Click to load it

As you seem to have already worked out, either

    if ($kind == \&some_sub)


    if (refaddr $kind == refaddr \&some_sub)

Quoted text here. Click to load it

If you are comparing to a literal ref you can skip the safety checks,
since refaddr returns undef if its argument isn't a ref. If $kind not
being a ref is an expected occurence, you may want to turn off
uninitialized value warnings.

Quoted text here. Click to load it

The XS version of Scalar::Util is core under 5.8.8 (corelist
Scalar::Util), so the PP version is irrelevant. (Tom is right that the
mechanism for finding the address in pure Perl is ridiculous, but it
does work reliably.)

Quoted text here. Click to load it

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.


Re: Comparing a reference?

Quoted text here. Click to load it

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->;
    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.

Tim McDaniel,

Re: Comparing a reference?

Quoted text here. Click to load it

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.

Tim McDaniel,

Site Timeline