In a comment on my UNIVERSAL::can module, someone asked "Why would a class override isa()
?"
Easy. Suppose your code is paranoid about the objects it receives to certain methods. You want to make sure that you don't call invalid methods on invalid invocants.
That's fine. That's good. You don't want your code to break.
Of course, you're totally fine breaking my code. What if I look carefully at the interface and behavior you require from such an object and write a proxy object that does absolutely everything right? There are lots of reasons to do this -- caching, autouse trampolines, testing with Test::MockObject, logging, debugging.
If I don't override isa()
in my class, your code vomits messily even if my object does exactly what your code needs it to do because all you care about is that the object you receive inherits from some base class. Yippee. You broke my code for no good reason.
That's why Perl 6 has roles and suggests that does()
is the question you should ask of a potential invocant instead of isa()
. That's why you can override isa()
in Perl 5.
If your code doesn't allow that (say -- if you use UNIVERSAL::isa()
as a function, not a method), your code is broken and wrong. Please fix it.
(Still don't believe me? Go break your own code for a change:
download Acme::UNIVERSAL::new and replace all of your constructor calls with calls to UNIVERSAL::new()
. If that doesn't make the problem abundantly clear, I don't know what else to say.)
Update: removed a clause that may have given offense. I apologize to everyone who read the previous version.
Re:Sigh...
chromatic on 2006-02-09T22:33:38
Maybe so, but I'm tired of explaining this issue to every person who files a bug report against one of my modules when the problem is that other people break my code by writing buggy code.
I'm very tired of explaining why this is a problem and what the fix is and being ignored, mocked, disbelieved, and blamed for it.
If, after all of that, someone can't look at
Acme::UNIVERSAL::new
and see why that doesn't work and realize that the exact same problem applies toUNIVERSAL::isa()
andUNIVERSAL::new()
, I don't have any hope for such a programmer.I don't mean to imply that any specific programmer who has disbelieved that this is a problem shouldn't be programming -- but anyone who refuses to acknowledge that this could possibly be a problem after all of this seems willfully blind to me.
I will strike out the sentence of great offense, though. Thank you for the suggestion.
Re:Sigh...
ChrisDolan on 2006-02-10T02:32:19
chromatic,
It took me a while to come around to your point of view and I think it's taking others a while too. The problem is that the buildin isa() and can() die on non-blessed objects and most people (me included) didn't think it was OK to wrap it in an eval{}. For me, I believed the dogma that eval"" is slow and bad and transferred that to eval{}.
Unfortunately, I believe that UNIVERSAL::{can,isa}.pm are fanning the flames more than strictly necessary. Yes, they *have* succeeded in getting people to talk about this issue, but they are sufficiently confrontational as to distract from the goal, I think.
I assert that it's time to release new versions of can.pm and isa.pm that are much less aggressive -- they silently try to work around the problem instead of issuing warnings and (in the case of isa.pm) have much more civil POD.
I think the single biggest success to date is getting perlobj.pm changed in 5.8.8. I've been pointing people to that.
Re:Sigh...
chromatic on 2006-02-10T02:59:04
Without the warnings, I'm not sure people would have found and reported the bugs they did, but I do understand your point about the tone of the documentation in
UNIVERSAL::isa
.I'm not sure what to say about the broken code other than that it's broken though. Ideally I wouldn't need to use these modules in
Test::MockObject.
Re:Sigh...
Alias on 2006-02-10T04:08:38
While I find their _tone_ overly confrontational in the docs, having UNIVERSAL::(isa|can) silently work around is the second worst possible solution (the worst being that they die or something).
There ARE cases for using UNIVERSAL::isa and and can directly, but they are few and far between and you really need to know what you are doing.
Personally, I think I've used it in CPAN module maybe a total of 6 times where you could change a UNIVERSAL::isa call ->isa and expect it to be correct. In 99% of cases you SHOULD be calling the it as a method (or using Params::Util::_INSTANCE for the DWIM approach).
And I for some am cool with locally turning off warnings for the _very_ few times someone might need it directly.
Re:Sigh...
Alias on 2006-02-10T04:10:05
ugh... I need to wake up more...
That should read,
"Personally, I think I've used them in a CPAN module maybe a total of 6 times where you couldn't change a UNIVERSAL::isa call ->isa and expect it to be correct. In 99% of cases you SHOULD be calling the it as a method (or using Params::Util::_INSTANCE for the DWIM approach).Re:Sigh...
Alias on 2006-02-10T04:11:46
</b>:(