http://qs1969.pair.com?node_id=217565

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

I have used the following logic to identify blessed things.
$is_blessed = $x =~ /=/; # ASSERTED: ref($x)

Somewhere years ago I got the impression that a stringified reference was defined to be of the form commonly seen:

Classname=Implementation_type(Hex_address)
or
TYPE(Hex_address)

But perlref for 5.8.0 says: Using a reference as a string produces both its referent's type, including any package blessing as described in perlobj, as well as the numeric address expressed in hex.

This doesn't guarantee the =, the (, the ) or the order of the other elements.

Is there any usage of stringified refs in existing code that would inhibit an alteration of their format? Or am I just a odd man out.

Replies are listed 'Best First'.
Re: stringified references
by adrianh (Chancellor) on Dec 04, 2002 at 19:32 UTC

    Since a developer can override stringification this isn't safe in general I'm afraid.

    Take a look at the blessed function in Scalar::Util. It does exactly what it says on the tin.

Re: stringified references
by particle (Vicar) on Dec 04, 2002 at 20:19 UTC

    see ref, no, maybe? for a good discussion on ref.

    i use the following, pinched and modified from a node in that thread.

    if( ! ref($r) ) { ## no ref here } elsif( ! eval { $r->can('isa') } ) { ## i'm an unblessed ref } else { ## i'm a blessed ref }

    ~Particle *accelerates*

Re: stringified references
by pg (Canon) on Dec 04, 2002 at 20:48 UTC
    The format you expected is still correct, although the document didn't say so, but ..., not just you can be cheated, even UNIVERSAL::isa can be cheated, try this:
    use IO::Socket::INET; use strict; my $socket = new IO::Socket::INET(); print $socket, "\n"; print "is INET\n" if UNIVERSAL::isa($socket, "IO::Socket::INET"); print "is Socket\n" if UNIVERSAL::isa($socket, "IO::Socket"); print "is IO\n" if UNIVERSAL::isa($socket, "IO"); print "is GLOB\n" if UNIVERSAL::isa($socket, "GLOB"); print "is HASH\n" if UNIVERSAL::isa($socket, "HASH"); $socket =~ s/GLOB/HASH/; print "after s///\n"; print $socket, "\n"; print "is INET\n" if UNIVERSAL::isa($socket, "IO::Socket::INET"); print "is Socket\n" if UNIVERSAL::isa($socket, "IO::Socket"); print "is IO\n" if UNIVERSAL::isa($socket, "IO"); print "is GLOB\n" if UNIVERSAL::isa($socket, "GLOB"); print "is HASH\n" if UNIVERSAL::isa($socket, "HASH");
      Umm, I'm not sure I got your point. Heres what I got when I played with your code...
      use IO::Socket::INET; use strict; use overload; use warnings; sub is_blessed { defined($_[0]) && ref($_[0]) && (index(overload::StrVal($_[0]),'=')>=0) && overload::StrVal($_[0])!~/^Regexp=SCALAR/? "blessed" : "not blesse +d"; } my $socket = IO::Socket::INET->new (); print overload::StrVal($socket),"is ",is_blessed($socket)," and\n"; foreach (qw(IO IO::Socket IO::Socket::INET GLOB HASH)) { print "is" .(UNIVERSAL::isa( $socket, $_ )? " a " : " not a ").$_. +"\n" ; } $socket =~ s/GLOB/HASH/; print "after s///\n"; print overload::StrVal($socket),"is ",is_blessed($socket)," and\n"; foreach (qw(IO IO::Socket IO::Socket::INET GLOB HASH)) { print "is" .(UNIVERSAL::isa( $socket, $_ )? " a " : " not a ").$_. +"\n" ; } __END__ IO::Socket::INET=GLOB(0x1ab52f0)is blessed and is not a IO is a IO::Socket is a IO::Socket::INET is a GLOB is not a HASH after s/// IO::Socket::INET=HASH(0x1ab52f0)is not blessed and is not a IO is not a IO::Socket is not a IO::Socket::INET is not a GLOB is not a HASH

      --- demerphq
      my friends call me, usually because I'm late....

Re: stringified references
by demerphq (Chancellor) on Dec 04, 2002 at 23:51 UTC
    From what I know you are almost correct. adrianh has the problem but missed* in the turgid docs of perldoc:overload the implication of overload::StrVal which will return the pattern you specify. If that changed an endless chunk of code would break. Including Data::Dumper. You, or I or someone should post a documentation patch to make it permanent however.

    Heres a more rigourous definition of a is_blessed test.

    $is_blessed = defined($x) && ref($x) && overload::StrVal($x) =~ /=/;
    Incidentally for this check its faster but less idiomatic to say
    $is_blessd=defined($x) && ref($x) && (index(overload::StrVal($x),'=')> +=0);
    BTW, only if you choose to consider qr// constructs to be blessed then this test is fine. If you dont then you need something like
    $is_blessd=defined($x) && ref($x) && (index(overload::StrVal($x),'=')> +=0) && overload::StrVal($x)!~/^Regexp=SCALAR/;
    PS: Im hoping that its obvious that you have to use overload; for all of this.

    Cheers,

    update:* I didnt mean to imply that he was wrong about the Scalar::Util approach. However it is an extra module and the code I mention should be fine without it. Although it is a lot faster to use than all of the above.

    --- demerphq
    my friends call me, usually because I'm late....

Re: stringified references
by John M. Dlugosz (Monsignor) on Dec 04, 2002 at 19:41 UTC
    Using ref and getting something back that's not a built-in type would indicate that it's blessed.
      my $foo = bless {}, 'ARRAY'; my $bar = []; print "ooops\n" if ref($foo) eq ref($bar);
      ;-)
Re: stringified references
by ehdonhon (Curate) on Dec 04, 2002 at 22:54 UTC
    $is_blessed = $x =~ /=/;       # ASSERTED: ref($x)

    It would seem to me that isn't such a good idea since it would be very easy to get a false positive regardless of the perl version...

    my $x = 'This code = boring'; $is_blessed = $x =~ /=/; print "Wrong" if $is_blessed;