Lightning Strikes Four Times
by Shlomi Fish, Bob Free, Mike Friedman, brian d foy
|
Pages: 1, 2, 3, 4
What's In that Scalar?
by brian d foy
Scalars are simple, right? They hold single values, and you don't even have to care what those values are because Perl figures out if they are numbers or strings. Well, scalars show up just about anywhere and it's much more complicated than single values. I could have undef, a number or string, or a reference. That reference can be a normal reference, a blessed reference, or even a hidden reference as a tied variable.
Perhaps I have a scalar variable which should be an object (a blessed reference, which is a single value), but before I call a method on it I want to ensure it is to avoid the "unblessed reference" error that kills my program. I might try the ref built-in to get the class name:
if( ref $maybe_object ) { ... }
There's a bug there. ref returns an empty string if the scalar isn't an object. It might return 0, a false value, and yes, some Perl people have figured out how to create a package named 0 just to mess with this. I might think that checking for defined-ness would work:
if( defined ref $maybe_object ) { ... }
... but the empty string is also defined. I want all the cases where it is not the one value that means it's not a reference.
unless( '' eq ref $maybe_object ) { ... }
This still doesn't tell me if I have an object. I know it's a reference, but maybe it's a regular data reference. The blessed function from Scalar::Util can help:
if( blessed $maybe_object ) { ... }
This almost has the same problem as ref. blessed returns the package name if it's an object, and undef otherwise. I really need to check for defined-ness.
if( defined blessed $maybe_object ) { ... }
Even if blessed returns undef, I still might have a hidden object. If the scalar is a tied variable, there's really an object underneath it, although the scalar acts as if it's a normal variable. Although I normally don't need to interact with the secret object, the tied built-in returns the secret object if there is one, and undef otherwise.
my $secret_object = tied $maybe_tied_scalar;
if( defined $secret_object ) { ... }
Once I have the secret object in $secret_object, I treat it like any other object.
Now I'm sure I have an object, but that doesn't mean I know which methods I can call. The isa function in the UNIVERSAL package supposedly can figure this out for me. It tells me if a class is somewhere in an object's inheritance tree. I want to know if my object can do what a Horse can do, even if I have a RaceHorse:
if( UNIVERSAL::isa( $object, 'RaceHorse' ) {
$object->method;
}
...what if the RaceHorse class is just a factory for objects in some other class that I'm not supposed to know about? I'll make a new object as a prototype just to get its reference:
if( UNIVERSAL::isa( $object, ref RaceHorse->new() ) {
$object->method;
}
A real object-oriented programmer doesn't care what sort of object it is as long as it can respond to the right method. I should use can instead:
if( UNIVERSAL::can( $object, $method ) {
$object->method;
}
This doesn't always work either. can only knows about defined subroutine names, and only looks in the inheritance tree for them. It can't detect methods from AUTOLOAD or traits. I could override the can method to handle those, but I have to call it as a method (this works for isa too):
if( $object->can( $method ) ) {
$object->method;
}
What if $object wasn't really an object? I just called a method on a non-object! I'm back to my original problem, but I don't want to use all of those tests I just went through. I'll fix this with an eval, which catches the error for non-objects:
if( eval{ $object->can( $method ) } ) {
$object->method;
}
...but what if someone installed a __DIE__ handler that simply exit-ed instead of die-ing? Programmers do that sort of thing forgetting that it affects the entire program.
$SIG{__DIE__} = sub { exit };
Now my eval tries to die because it caught the error, but the __DIE__ handler says exit, so the program stops without an error. I have to localize the __DIE__ handler:
if( eval{ local $SIG{__DIE__}; $object->can( $method ) } ) {
$object->method;
}
If I'm the guy responsible for the __DIE__ handler, I could use $^S to see if I'm in an eval:
$SIG{__DIE__} = sub { $^S ? die : exit };
That's solved it, right? Not quite. Why do all of that checking? I can just call the method and hope for the best. If I get an error, so be it:
my $result = eval { $object->method };
Now I have to wrap all of my method calls in an eval. None of this would really be a problem if Perl were an object language. Or is it? The autobox module makes Perl data types look like objects:
use autobox;
sub SCALAR::println { print $_[0], "\n" }
'Hello World'->println;
That works because it uses a special package SCALAR, although I need to define methods in it myself. I'll catch unknown methods with AUTOLOAD:
sub SCALAR::AUTOLOAD {}
Or, I can just wait for Perl 6 when these things get much less murky because everything is an object.

