[ Team LiB ] Previous Section Next Section

Recipe 13.9 Determining Subclass Membership

13.9.1 Problem

You want to know whether an object is an instance of a particular class or that class's subclasses. Perhaps you want to decide whether a particular method should be invoked on an arbitrary object.

13.9.2 Solution

Use methods from the special UNIVERSAL class:

$obj->isa("HTTP::Message");                  # as object method
HTTP::Response->isa("HTTP::Message");        # as class method

if ($obj->can("method_name")) { .... }       # check method validity

13.9.3 Discussion

Wouldn't it be convenient if all objects were rooted at some ultimate base class? That way you could give every object common methods without having to add to each @ISA. Well, you can. You don't see it, but Perl pretends there's an extra element at the end of @ISA—the package named UNIVERSAL.

UNIVERSAL has only a few predefined methods, although you are free to add your own. These are built right into your Perl binary, so they don't take extra time to load. Predefined methods include isa, can, and VERSION. All three may be used for both sorts of invocants: classes and objects.

The isa method reports whether its invocant inherits the class name directly or indirectly from the class name supplied as the argument. This saves having to traverse the hierarchy yourself, and is much better than testing with an exact check against the string returned by the ref built-in. You may even supply a basic type that ref might return as an argument, such as SCALAR, ARRAY, HASH, or GLOB.

$has_io = $fd->isa("IO::Handle") || $fd->isa("GLOB");
$itza_handle = IO::Socket->isa("IO::Handle");

Type checks like this are sometimes frowned upon as being too constraining. If you just want to know if a certain method can be invoked against something, it might be better to just try to invoke the method you're hoping will be there instead of checking for the class.

Another possibility is to use another UNIVERSAL method, can. The can method reports whether its string argument is a valid method for its invocant. In fact, it even returns a function reference for that method:

$his_print_method = $obj->can('as_string');

Finally, the VERSION method checks whether the invocant class has a package global called $VERSION that's high enough, as in:

Some_Module->VERSION(3.0);
$his_vers = $obj->VERSION( );

However, we don't usually invoke VERSION ourselves. Remember, in Perl an all-uppercase function name means that the function will be automatically called by Perl in some way. In this case, it happens when you say:

use Some_Module 3.0;

If you wanted to add version checking to your Person class explained earlier, add this to Person.pm:

our $VERSION = "1.01";

Then, in the user code say use Person 1.01; to make sure that you have at least that version number or higher available. This is not the same as loading in that exact version number; it just has to be at least that high. Lamentably, no mechanism for concurrent installation of multiple versions of a module yet exists.

13.9.4 See Also

The documentation for the standard UNIVERSAL module; the use keyword in perlfunc(1) and in Chapter 11 of Programming Perl

    [ Team LiB ] Previous Section Next Section