in reply to Re^2: A Scalar::Util::refaddr Oddity
in thread A Scalar::Util::refaddr Oddity

I don't understand why the pure-perl version uses that code versus the 0 + $object idiom.

Because that idiom fails if $object overloads addition to do something else.

Replies are listed 'Best First'.
Re^4: A Scalar::Util::refaddr Oddity
by xdg (Monsignor) on Sep 26, 2005 at 13:54 UTC
    Because that idiom fails if $object overloads addition to do something else.

    Doh! (Can you tell I don't mess with overloading much? Wasn't even on my radar screen.) OK, then, quick perusal of overload reveals the StrVal function, which can get us back to the original "grab the right substring and convert" approach without the reblessing.

    use strict; use warnings; use Scalar::Util qw( refaddr ); package Foo; use overload '0+' => sub { 0 }, q{""} => sub { "Some Object" }, fallback => 1; package main; use overload; sub refaddr_pp { return if not ref $_[0]; overload::StrVal($_[0]) =~ /0x(\w+)/; return hex $1; } my $obj = bless {}, 'Foo'; my $ref = {}; print 'stringify $obj: ', "$obj", "\n"; print 'refaddr $obj: ', refaddr($obj), "\n"; print 'refaddr_pp $obj: ', refaddr_pp($obj), "\n\n"; print 'stringify $ref: ', "$ref", "\n"; print 'refaddr $ref: ', refaddr($ref), "\n"; print 'refaddr_pp $ref: ', refaddr_pp($ref), "\n\n";

    Prints

    stringify $obj: Some Object refaddr $obj: 155892768 refaddr_pp $obj: 155892768 stringify $ref: HASH(0x94abd10) refaddr $ref: 155893008 refaddr_pp $ref: 155893008

    -xdg

    Code written by xdg and posted on PerlMonks is public domain. It is provided as is with no warranties, express or implied, of any kind. Posted code may not have been tested. Use of posted code is at your own risk.

      That would work - but pulling in overload seems overkill when we can just use Scalar::Util::blessed to see whether the reblessing hack is necessary.

        You're the benchmark master. ;-) One-time hit to require overload and then a single function call, or always check blessed, store the original package and bless twice?

        Or how about this -- so we only use it if something else has loaded overload and the object is actually overloaded?

        sub refaddr_pp { return if not ref $_[0]; if ( exists $INC{'overload.pm'} && overload::Overloaded($_[0]) ) { overload::StrVal($_[0]) =~ /0x(\w+)/; return hex $1; } else { return 0 + $_[0]; } }

        -xdg

        Code written by xdg and posted on PerlMonks is public domain. It is provided as is with no warranties, express or implied, of any kind. Posted code may not have been tested. Use of posted code is at your own risk.

      Your code introduces a bug not in the original, here:

      overload::StrVal($_[0]) =~ /0x(\w+)/;

      You use the same regexp as the original, but because you are no longer blessing into a known package the regexp may match the package name instead of the address. Indeed, a bug common enough to warrant the introduction of a new fatal error in perl-5.8 would give rise to exactly that situation:

      zen% cat t0 package A; $x = bless {}; $y = bless [], $x; print "$y"; zen% /opt/perl-5.6.1/bin/perl -wl t0 A=HASH(0x811198c)=ARRAY(0x8111a94) zen% /opt/perl-5.8.0/bin/perl -wl t0 Attempt to bless into a reference at t0 line 1.

      Admittedly it is harder to get an overloaded object inadvertently in the wrong class like this, but "0x" is not so unusual a sequence of characters that it is fair to assume it will never appear in a legitimate package name. In any case it is easy enough to fix, with either /.*0x(\w+)/ or /0x(\w+)\)\z/.

      Hugo

Re^4: A Scalar::Util::refaddr Oddity
by BrowserUk (Patriarch) on Sep 26, 2005 at 12:39 UTC

    Wouldn't blessing a copy of the reference in order to extract the address work, and allow the blessed copy to be discarded leaving the original unmodified?


    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?
    "Science is about questioning the status quo. Questioning authority".
    The "good enough" maybe good enough for the now, and perfection maybe unobtainable, but that should not preclude us from striving for perfection, when time, circumstance or desire allow.
      Wouldn't blessing a copy of the reference in order to extract the address work, and allow the blessed copy to be discarded leaving the original unmodified?

      Nope. Blessedness is associated with the referent not the reference. For example:

      use Test::More 'no_plan'; my $original = bless {}, 'Something'; isa_ok $original, 'Something'; my $copy = $original; bless $copy, 'SomethingElse'; isa_ok $original, 'SomethingElse'; __END__ ok 1 - The object isa Something ok 2 - The object isa SomethingElse 1..2
Re^4: A Scalar::Util::refaddr Oddity
by ambrus (Abbot) on Sep 26, 2005 at 17:00 UTC

    Anyway, after reblessing the object, wouldn't it be better to take the reference in numeric context than to extract the number from the string form?

      Anyway, after reblessing the object, wouldn't it be better to take the reference in numeric context than to extract the number from the string form?

      True, although I've no idea off the top of my head whether that behaviour has always been in Perl so there may be issues with the perl versions that Scalar::Util supports.

        You might be right... the phrase
        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.
        has got into perlref between 5.005 and 5.6.0. The feature might have been there from the start though.

      If it's backwards compatible, and if speed is the utility function, yes. Surprisingly, unless I'm missing something, it's even faster than refaddr, at least for my environment (perl 5.8.6 on linux i386).

      Update: clearly, what I'm missing is reading the docs to Benchmark and proofreading my code. Stupid errors fixed, I hope. 0 + $ref still seems to be faster than the XS refaddr, which is surprising, but maybe that's the function call overhead.

      use strict; use warnings; use Scalar::Util qw( refaddr ); use Benchmark qw( cmpthese ); my $ref = {}; cmpthese( -5, { 'xs ' => sub { refaddr $ref }, 'regex' => sub { "$ref" =~ /0x(\w+)/; hex $1; }, '0+ref' => sub { 0 + $ref }, });

      Result:

      Rate regex xs 0+ref regex 165816/s -- -89% -97% xs 1504549/s 807% -- -73% 0+ref 5550057/s 3247% 269% --

      -xdg

      Code written by xdg and posted on PerlMonks is public domain. It is provided as is with no warranties, express or implied, of any kind. Posted code may not have been tested. Use of posted code is at your own risk.