I know that 'can' method inspects if package has the method 'some_method'. But, what is happening in the "->(animal => $x)" part?
$z = __PACKAGE__->can("some_method")->(animal => $x)
I know that 'can' method inspects if package has the method 'some_method'. But, what is happening in the "->(animal => $x)" part?
$z = __PACKAGE__->can("some_method")->(animal => $x)
can() will return reference to method if it exists and then method will be dereferenced with "dereferencing arrow". You must wrap this into eval, or exception will rise if "some_method" doesn't exist. Read more here:
About can(): perldoc UNIVERSAL
About dereferencing of subroutines: perldoc perlref
The can returns a code reference to the method. Perl "methods" are just normal Perl subroutines that expect the class or object (the "invocant") as the first argument.
sub some_method {
my( $self, @args ) = @_;
...
}
In the arrow notation, the invocant is on the left and the method is on the right:
$object->method();
That's really a call of a subroutine in the invocant's package where the invocant becomes the first argument:
SomePackage::method( $object )
Remember, an object is merely a blessed reference, which means the reference has been labelled with a package name. We call that an "object", and when you call a method on an object, it uses that label to determine where to start looking for the right subroutine to use.
Calling it this way directly ignores several object orientation features though. You won't use inheritance, for example. You are directly calling a particular subroutine rather than letting Perl find the appropriate method.
So, back to your code. The can can search through the inheritance tree to find a subroutine to call. It might not be in the package you start with. It then returns a code reference for whatever it found, but you don't know which package supplied that subroutine. You also don't know who asked for the code reference.
You have the code reference now and you want to call it. You have to supply the invocant on your own:
$coderef->( INVOCANT, @args );
Someone has decided that "animal" (a simple string, which means this might be a class method) is the right invocant. The first argument to this code is not an object:
$coderef->( 'animal', @args );
But, don't use code like that. Almost no one does that and it's subverting many of the advantages of object-oriented code. I tend to write it more like:
if( eval { __PACKAGE__->can('some_method') } ) {
__PACKAGE__->some_method( @args );
}
Note that using __PACKAGE__ here is also weird (this coming from a habitual abuser of that). I suspect that if you are using that, there's a better way to accomplish the task.