I have method in a class that I need to make sure is only called on an object instance, and not as a class method.
I will probably do something like this:
# Edit: this is terrible, don't do this, it breaks inheritance.
sub foo
{
my ($self) = @_;
if (ref($self) ne __PACKAGE__) { return; }
...do stuff
}
But I'm thinking it will be more efficient to do this:
sub foo
{
my ($self) = @_;
if (not ref($self)) { return; }
...do stuff
}
Questions:
Is it safe to assume that if ref() returns not undef that it will return the current package?
I would ideally like to go back through and do something like this in all my methods for sanity checking. Is that a bad idea?
Is there a more perlish way to do what I want?
"Use moose" is not an acceptable answer in this case. However if you are compelled to say that, please tell me how moose makes this easy or more efficient. I might want to incorporate it into my own object system.
Thanks!
EDITED to reflect that ref never returns undef, only an empty string.
EDIT 2 Here's a follow up question. Someone below suggested using:
$self->isa(__PACKAGE__)
But won't that always succeed? Unless of course the caller does something really boneheaded like:
MyClass::MyMethod($ref_to_some_other_object)
First, you should probably croak rather than silently doing nothing because, according to your specs, calling foo as a class method is a breach of contract.
Second, just checking if the first argument is a reference is enough. Your method will fail if there is inheritance involved:
#!/usr/bin/perl
package A;
use Carp;
sub new { bless {} => shift }
sub foo {
croak "I am not in " . __PACKAGE__ unless __PACKAGE__ eq ref(shift)
}
package B;
use base 'A';
package main;
$x = B->new;
$x->foo;
C:\Temp> t I am not in A at C:\Temp\t.pl line 19
See also perldoc -f ref:
If the referenced object has been blessed into a package, then that package name is returned instead. You can think of
refas atypeofoperator.
So:
sub foo {
croak "Don't call as class method" unless ref shift;
}
Finally, note that ref never returns undef.
Is it a good idea to add this check to every method? I guess one could make that argument from a design by contract view.
On the other hand, my methods assume they were called as instance methods and I only check for the possibility of a method being called as a class method if the method can provide a meaningful alternative behavior when called as such.
I cannot remember any modules which have these kinds of checks either.
By the way, instead of
sub foo {
my ($self) = @_;
you should use
sub foo {
my $self = shift;
leaving only the arguments to the method in @_ to be unpacked. Or, you should unpack all arguments in one fell swoop:
sub foo {
my ($self, $bar, $baz) = @_;
Is it safe to assume that if ref() returns not undef that it will return the current package?
No.
my $bar = Bar->new;
Package::Foo::foo($bar);
will lead to foo putting $bar into $self and ref $self will then return Bar.
And, as already noted in the earlier answers, checking for the literal package name rather than testing isa breaks inheritance anyhow.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With