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

Dear Monks.

In http://search.cpan.org/~rgarcia/perl-5.10.0/lib/UNIVERSAL.pm it is written:
# but never do this! $is_io = UNIVERSAL::isa($fd, "IO::Handle"); $sub = UNIVERSAL::can($obj, "print");

But I don't get it. Why should I never do this and prefer
$is_io = $fd->isa('IO::Handle');
?
Thank you for your answers!

k

Replies are listed 'Best First'.
Re: Do not use UNIVERSAL::isa this way; but why?
by Tanktalus (Canon) on Dec 10, 2008 at 15:07 UTC

    Because a class can override isa to return what it wants, and you're bypassing that.

    package MyIO; sub isa { my $self = shift; my $type = shift; return 1 if $type eq 'IO::Handle'; return $self->SUPER::isa($type); }
    In this scenario, MyIO wants to claim to be an IO::Handle. That's perfectly allowed - presumably, then, it fulfills all the obligation of IO::Handle without actually deriving from it. Another example:
    package MyNotIO; use base 'IO::Handle'; sub isa { my $self = shift; my $type = shift; return 0 if $type eq 'IO::Handle'; return $self->SUPER::isa($type); }
    In this case, I don't want to look like an IO::Handle, even though I'm derived from it. Maybe I just want all the convenience of the IO::Handle type, while breaking its interface. Again, your UNIVERSAL::isa($obj, 'IO::Handle') would return incorrectly because it wouldn't be using this isa.

    The problem with $fd->isa(...) is that it crashes if $fd is undef, whereas a simple "no" would be better. If they made that work at the same time as inheritance, that'd be awesome :-) Most likely, that would just be:

    package UNIVERSAL; sub safe_isa { my $obj = shift; return unless defined $obj and ref $obj; $obj->isa(@_); }
    Now you could call UNIVERSAL::safe_isa($fd, 'IO::Handle'), and it'd work properly, and safely, even if $fd wasn't actually an object.

      The problem with $fd->isa(...) is that it crashes if $fd is undef, whereas a simple "no" would be better. If they made that work at the same time as inheritance, that'd be awesome :-) Most likely, that would just be:

      The idiom is to wrap it in an eval:

      my $answer = eval { $fd->isa(...) };

      If it's not an object or isn't the right type, you get false. It doesn't matter to you why it is false because in both cases it's not the object type you are looking for.

      --
      brian d foy <brian@stonehenge.com>
      Subscribe to The Perl Review
Re: Do not use UNIVERSAL::isa this way; but why?
by Bloodnok (Vicar) on Dec 10, 2008 at 15:18 UTC
Re: Do not use UNIVERSAL::isa this way; but why?
by klekker (Pilgrim) on Dec 10, 2008 at 21:09 UTC
    Thank you all for your answers!

    Well then... I think I'll 'switch' to
    $is_my_class = defined($object) && $object->isa('My::Class');
    since I used to write
    $is_my_class = defined($object) && $UNNIVERSAL::isa($object, 'My::Clas +s');
    or
    $is_my_class = eval { $fd->isa('My::Class') };
    to preserve my keyboard! ;)

    @ Tanktalus: uh... I've never thought about this. But I think I... yeah... the time will come when I'll have to write a Decorator! At least this came to my mind when I read your post.

    k
      *narg*
      Typo respectively wrong. I won't use
      $is_my_class = defined($object) && $object->isa('My::Class');
      because if $object is defined but not blessed...

      I'll use
      $is_my_class = eval { $fd->isa('My::Class') };
      although normally (and I don't know why) I try to avoid 'eval'.
      And although I'm not sure if I like this statement.
      k
Re: Do not use UNIVERSAL::isa this way; but why?
by DrHyde (Prior) on Dec 12, 2008 at 10:51 UTC

    The documentation is wrong.

    While the point another commenter made about can and isa being overridden is valid, that doesn't mean that you should never use them like that. Just that you should be really sure that that's what you want to do.

      Just that you should be really sure that that's what you want to do.

      And when would it be what you want to do? No, ->isa is always the way to go. Feel free to wrap it in an eval if you need.

      my $isa = eval { $questionable->isa($class) };
Re: Do not use UNIVERSAL::isa this way; but why?
by roman (Monk) on Dec 13, 2008 at 12:32 UTC

    What do you think about using UNIVERSAL::isa on unblessed reference. Is it safe (recommendable)?

    # checking whether argument is a subroutine reference if (!UNIVERSAL::isa($callback, 'CODE')){ } # popping last option parameter my $options_ref = @_ && UNIVERSAL::isa($_[-1], 'HASH')? pop(): {};
      If you are expecting a reference I would not recommend using UNIVERSAL::isa this way because the next one who has to deal with your code could believe that there is an object called 'HASH'. (Although this seems not to be very likely but I've seen worse things... :/ ).
      If you want to check a reference I would advise you to keep using ref().