... so I leave the decision as to whether to call the method to run time where I check that the method exists by calling can, and then do one thing if it does and another if it doesn't.
This is the 'plug-in' scenario.
You could also do:
sub Another::Module::particularMethod {
my $o = shift;
...
eval{ $o->method( ... ); }
if( $@ =~ q[^Can't locate object method "method"] ) {
do{ oneThing() };
}
else {
do{ anotherThing() };
}
...
}
Still a run-time decision. But, it can be done this way in any language that supports exceptions. No need for the inclusion of RTTI tables, or picking apart the bytecode.
Is there any advantage to doing it this way?
I think yes. Just because a class has a method named X, doesn't mean that X is what you think it is.
- That it takes the same number of parameters as you're expecting.
- Or the same types of parameters you're expecting.
With some reflection APIs (eg. Java), you can discover both of these. At a considerable cost of decompiling the byte code at run-time. And at the further considerable cost of programming the logic in your code, to iterate the known public methods, with the particular name you're interested in and then check the number, and types of the parameters they expect, and the type they return.
But even then, having done all of that discovery, you still don't know whether it:
- Will actually implement the same semantics as you want it to.
Even after you've been through the laborious process of run-time discovery, when you (or whomever) eventually gets around to invoking the method, it may still raise an exception--either an 'expected' one due to bad input, or an unexpected one due to it's semantic being entirely different to what you are hoping for. Ie. Instead of calculating some statistics, it trying to wipe your harddrive.
So, when you eventually do get around to calling the method, you're going to have to wrap the call in an exception handler anyway. So why not skip all the slow, laborious and run-time costly discovery, and just try invoking it?
Simpler (less), clearer (it worked or it didn't; rather than: it might work(or not), it still might work(or not); it still might work(or not); it worked(or not)) code.
Same final effect.