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

Of late, it's been recognized that a class's isa and can methods might supercede &UNIVERSAL::isa and &UNIVERSAL::can especially when &AUTOLOAD is involved. To that end, the best practices recommendation is now eval { $obj->isa( ... ) } and eval { $obj->can( ... ) }. This covers the case where $obj isn't a reference, is an unblessed reference, is an object without a special isa or can, or is an object with with special isa or can.

What of ref()? Recently I started feeding proxy objects to B::Deparse but found that I had to override CORE::ref and recompile B::Deparse. That is, I had no way of letting my proxy object lie to ref() short of something extremely crude and targetted to the one thing I wanted to lie to.

I'd like a better suggestion. What's the best way to use ref()?

Replies are listed 'Best First'.
Re: Overloading ref() just like ->isa and ->can?
by dragonchild (Archbishop) on Apr 18, 2006 at 16:16 UTC
    Actually, the best practices recommendation should be:
    eval { local $SIG{__DIE__}; $obj->isa( ... ); }
    Otherwise, you will trigger all SIGDIE handlers and, not surprisingly, Test::More has one.

    My criteria for good software:
    1. Does it work?
    2. Can someone else come in, make a change, and be reasonably certain no bugs were introduced?
      Otherwise, you will trigger all SIGDIE handlers and, not surprisingly, Test::More has one.
      Test::Builder, actually. To whit:
      $SIG{__DIE__} = sub { # We don't want to muck with death in an eval, but $^S isn't # totally reliable. 5.005_03 and 5.6.1 both do the wrong thing # with it. Instead, we use caller. This also means it runs under # 5.004! my $in_eval = 0; for( my $stack = 1; my $sub = (CORE::caller($stack))[3]; $stack+ ++ ) { $in_eval = 1 if $sub =~ /^\(eval\)/; } $Test_Died = 1 unless $in_eval; };
      I'm afraid that eval{} users have to be allowed the ease-of-coding advantage over die-handlers. The whole purpose of eval is to catch an exception; you shouldn't have to go through additional hoops to protect against an exception. Yes, there's a perl design botch, but eval{} shouldn't have to suffer for it. (As far as I know, $^S is working in newer perls, which should make things a little easier.)
Re: Overloading ref() just like ->isa and ->can?
by chromatic (Archbishop) on Apr 18, 2006 at 18:30 UTC

    I find the best approach is to find the person who sneaked it into the code and administer friendly beatings until it disappears. ref breaks polymorphism. That's a no-no.

      You mean like HTML::Template?

      My criteria for good software:
      1. Does it work?
      2. Can someone else come in, make a change, and be reasonably certain no bugs were introduced?

        Yep. If a properly-implemented proxied or tied object won't make it through the ref call correctly, it's the use of ref that's wrong.

Re: Overloading ref() just like ->isa and ->can?
by Roy Johnson (Monsignor) on Apr 18, 2006 at 16:04 UTC
    I am not sure, but I think you might be wanting Scalar::Util's blessed function. Or possibly reftype

    Caution: Contents may have been coded under pressure.
Re: Overloading ref() just like ->isa and ->can?
by creamygoodness (Curate) on Apr 18, 2006 at 16:21 UTC

    What are you hoping to get out of ref() and what is it giving you now when you feed it your faker-objects?

    Incidentally, if Scalar::Util's blessed() is available, $result = blessed($maybe_obj) and $maybe_obj->isa( ... ); might be faster than eval { $result->isa( ... ) };.

    Rate eval2 blessed1 eval1 blessed2 eval2 6.80/s -- -57% -61% -76% blessed1 15.9/s 134% -- -9% -43% eval1 17.4/s 156% 10% -- -38% blessed2 28.0/s 313% 76% 61% --

    Here's the test script:

    --
    Marvin Humphrey
    Rectangular Research ― http://www.rectangular.com

      When foreign code uses ref() on a proxy object, it sees the proxy object's class, not the class that the object is proxying for. The proxy object would need the foriegn code to be told that the proxy object is of the proxied class. That is, ref( $obj ) or its equivalent that I'm inquiring about would not return $obj's class but the class that $obj is proxying for. This looks like the same problem that UNIVERSAL::isa and UNIVERSAL::isa were created for.

      ⠤⠤ ⠙⠊⠕⠞⠁⠇⠑⠧⠊

Re: Overloading ref() just like ->isa and ->can - best practice for isa(HASH)?
by imp (Priest) on Aug 22, 2006 at 14:04 UTC
    What would be the best practice method for determining if something is a hash or array? At times I want to know that the underlying object is a hashref, even if it has been blessed. e.g.
    use strict; use warnings; { package foo; sub new { bless {}, shift}; } my $foo = foo->new(); print "ref(foo) = ",ref($foo), "\n"; print "foo is a hash\n" if UNIVERSAL::isa($foo,'HASH'); my $bar = {a => 1}; # The following won't work # print "bar is a hash\n" if $bar->isa('HASH'); print "bar is a hash\n" if UNIVERSAL::isa($bar,'HASH');

      If you want to know whether it really, truely is a hash, see if SVt_PVHV is true for the SV. See sv.h for the dirt.

      use B qw( svref_2object SVt_PVHV ); sub is_hash { my $ref = shift @_; return ref( $ref ) and svref_2object( $ref ) & SVt_PVHV; }

      If you just want to know whether it supports being treated like a hash, do something akin to a ->can test for hash-ness. If the hash dereference doesn't die, then $ref acts like a hash.

      sub does_hash { my $ref = shift @_; return ref( $ref ) and eval { %$ref; 1 }; }

      ⠤⠤ ⠙⠊⠕⠞⠁⠇⠑⠧⠊