tags:

views:

113

answers:

3

I want to use a method of an object. Like $myObject->helloWorld().

However there are a couple of methods so I loop through an array of method names and call the method like this:

my $methodName ="helloWorld";
$myObject->$methodNames;

This works quite nice but some objects don't have all methods.

How can I tell whether $myObject has a method called helloWorld or not?

+7  A: 

You can use the UNIVERSAL::can method of all objects to determine what methods it supports:

if ($myObject->can($methodName)) {
    $myObject->$methodName;
}
Eric Strom
+1... FGITW :))
DVK
+8  A: 

As Eric noted, you can usually use UNIVERSAL::can

It can be used either on an object as in your example ($obj->can($methodName)) or statically, on a class: (CLASS->can($methodName))

Please note that there are possible false negatives associated with using UNIVERSAL::can on objects/classes which have AUTOLOAD-ed methods - see the perldoc for details. So before using can() on an object/class, please be careful to verify that the class in question either does not use AUTOLOAD, or overrides can() to compensate, or uses forward declaration to compensate as described in can()'s perldoc - hat tip to brian d foy)

Also, please be careful to either ONLY call can() on actual objects, or encapsulate it in eval. It will die if called on a non-object (e.g. undef, scalar etc...)

DVK
I think you mean "false positives". It'd bet that many packages can `carp` or `croak` for even `first` for that matter. But just because it "croaks" doesn't mean it's a frog.
Axeman
@Axeman - I think false negative. As in, the package doesn't know it can call MyMeth1, because it's AUTOLOADed, and "can" returns "false"
DVK
A package that AUTOLOADs should also overload can to return the right answer. It's a design bug if it doesn't.
brian d foy
@brian - correct. The question and answer were from the POV of a caller, who can not necessarily depend on the class they use to NOT have that (IMHO subtle) bug (e.g. need to verify that it does indeed get resolved by the class prior to using `can`). I'll update the answer.
DVK
@brian - Yet Another Reason why "Perl Best Practices" is right about not using AUTOLOAD - don't recall if that reason is stated in the book explicitly :)
DVK
That's doesn't make _Perl Best Practices_ right at all. I reject your very premise.
brian d foy
@brian - do you explicitly explain why you consider PBP to be wrong about AUTOLOAD anywhere? You referred to that in a deleted answer to this: http://stackoverflow.com/questions/2460787/when-should-i-use-perls-autoload - but your answer didn't have specific use case where AUTOLOAD would be the best approach. If you didn't publish that reasoning/example anywhere, do you mind if I make it into a new question and hope for you to answer? Thanks!
DVK
@brian, sure its a design bug to fail to ensure that `can` will operate properly if you AUTOLOAD. It's an obvious error, once you see it. Until you've had it pointed out, it isn't such an obvious issue. But that's OK as long as the issue is well documented. I searched perldoc. I didn't find anything that states that use of `AUTOLOAD` should be matched with an overloaded `UNIVERSAL::can`. The docs for `UNIVERSAL` mention the problem and suggest predeclaring methods with `use sub`. There is no mention of the issue in `perlsub`. `perltoot` introduces AUTOLOAD, but makes no mention of the issue.
daotoad
@daotoad: then patch the docs. :) Remember, the Perl docs are a reference to a language, not a tutorial on programming. AUTOLOAD doesn't imply an interface, so there's not a requirement that anay autoloaded method should respond to can() with true. You can use AUTOLOAD in a variety of ways.
brian d foy
@DVK: How about you come up with the answer on your own? Seriously, you have the skills. Think about it for a long time, consider all the ramifications, and come to some conclusions. If you practice that skill you won't have to ask those sorts of questions: http://meta.stackoverflow.com/questions/13611/why-dont-high-rep-users-ask-questions
brian d foy
@brian, IMO, the best would be to alter the AUTOLOAD feature in some way so that the autoload subroutine would handle both sub call and `can` tests. This gets rid of the need to repeat logic (do I handle this routine), boilerplate code, potential bugs and extra docs. Better yet, a truly clever solution would work so well that in most cases existing code would just work. Unfortunately, I'm not clever enough to come up with anything other than a flag for AUTOLOAD subs to check for can vs call.
daotoad
@daotoad: you're assuming that all AUTOLOADed routines should be part of the public interface. That's just not so. And, I'm sure you're clever enough to come up with a solution if you tried. :)
brian d foy
@brian - (1) I have no idea what you meant by that since the link is to the question I have never seen before, never mind asked. (2) In my many years of writing fairly involved Perl modules I have never encountered a situation I could not resolve in a way which I considered to be better than AUTOLOAD. If you don't feel like elaborating why you disagree with Damien, that's fine. No need to be snarky when someone asks your reasoning on what is an obviously unsettled and unclear question.
DVK
@DVK: I see your point. Both seem to be an issue. But I agree with Brian's statement (yeah, I capitalized your name) that if you AUTOLOAD you ought to override `can`.
Axeman
@DVK: I'm not being snarky. I'm encouraging you to explore the issue on your own rather than rely on someone else to tell you the answer. That meta thread talks about why some people seem to ask questions while other people seem to answer them. Become one of the people that answer them. :)
brian d foy
@brian - as I said, my answer to this one is "no circumstances exist where a solution with AUTOLOAD is better - according to my priorities - than a solution other than AUTOLOAD" - this is AFTER many years of writing code that generated methods dynamically, on the fly, via templates, created packages dynamically, you name it. Since the conclusion obviously differs from yours, I was curious about your reasoning since you know more tricks and have deeper experience that I do.
DVK
@brian - BTW, while I'm not in your/Sinan's league, I have 9 times as many answers as Qs on SO and 92% of my SO rep is from answers. I think that ougght to qualify me for the "one of the people that answer questions" t-shirt :)
DVK
+4  A: 

The canonical way to use can is inside an eval block in case the thing that you have in your scalar variable isn't actually an object. You don't have to worry about that because you'll still get the right answer (a non-object or class can't respond to the method):

 if( my $ref = eval { $obj->can( $method ) } )
      {
      $obj->$ref( @args );
      }

The can has the added feature that it returns a code reference to the method. Sometimes that can be handy.

brian d foy
don't you need to pass the object as the first argument?
Eric Strom
Yeah, this wants to be `$obj->$ref(@args)` or `$ref->($obj, @args)` (equivalent, but less pretty :)
hobbs
You know, both of you do have edit powers. The wiki concept doesn't work so well when you spot mistakes that you don't fix. :)
brian d foy