All the Perl that's Practical to Extract and Report

Navigation

The Fine Print: The following comments are owned by whoever posted them. We are not responsible for them in any way.
Without JavaScript enabled, you might want to
use the classic discussion system instead. If you login, you can remember this preference.

Please Log In to Continue

I agree with you and Dave about the fragile inheritance problem (and wonder if adding hook methods [martinfowler.com] or migrating to a Class::Std [cpan.org]-based object model would solve some of these problems.

However, one of your suggestions makes a similarly unwarranted assumption, specifically:

I'm not sure how to take or answer that question. So I should never use UNIVERSAL::can because you may want to override it?:-)

Of course, I didn't have to check the method I'm referenceing exists at all. It just seemed like a safety measure. But then again, if you override anything in UNIVERSAL, its effects are your problem, not the modules authors problem right?

Or, was this comment geared towards the UNIVERSAL::can vs. $object->can debate that flares up from time to time?:-)

Yes, it's the great "Why in the world are you explicitly calling the parent implementation of a method on an instance of a known-derived class?" debate. Someday I'm going to write UNIVERSAL::new and write code that calls that directly instead of the actual constructors just to show how stupid a debate it is.

I'll admit, I'm a tard when it comes to that debate. I've heard mutterings and seen people use can both ways. In an effort to make me less stupid, care to elaborate on the difference between the two in the context of that debate?

can() is an object method. There's a default implementation in the UNIVERSAL base class so that classes that don't need to define their own implementations can inherit it.

Classes for which the default implementation is unsuitable can override it with their own implementations -- and there are good reasons for doing so, such as if you have a proxying or delegation relationship you want to keep transparent, if you autogenerate methods you can't know at compile time and don't necessarily want to install them in the symbol table before other code calls them, and so on. As long as the overridden method provides the same interface as UNIVERSAL::can(), the location of the implementation and the mechanics of the implementation are transparent to the caller. That's one important point of OO.

By calling can() as a method on an invocant, everything is fine. This will dispatch the right method regardless of whether the class has inherited the method from UNIVERSAL, from a parent somewhere, or has implemented its own. A class that has no special needs for this method will always answer the question "Do you respond to a method of this name?" appropriately. So will a class that needs to do different work to answer the question correctly.

Calling UNIVERSAL::can() as a function on an invocant explicitly forbids the invocant's class from overriding can(), even if it makes sense for that class to do so -- even if the class has already done so! This will sometimes answer the question incorrectly and sometimes will break perfectly legitimate code written by other people.

The other position in the debate is basically "So what? I don't care if code breaks", which I completely fail to understand and consider myself unqualified to summarize in more detail.

Would it be safe to assume that I should always use ->can against other classes, but if I was overriding and making my own can() sub, that the guts of my new and improved can() should use UNIVERSAL::can; or should it use $self->SUPER::can?

I think that you're unfairly summarizing the other position in the debate.

The other position as I see it can be summarized as, I think it more likely that some idiot who doesn't know about UNIVERSAL::can will write a can method that does the wrong thing, than that some smart guy will write a can method that works where UNIVERSAL::can would have failed.

Which is a vote of non-confidence in others, not a desire to see things break.

Just because the argument looks silly doesn't mean that it is wrong.See this thread [perlmonks.org] where multiple good programmers, having just been told what some of the problems are trying to mix AUTOLOAD and can, tried to write a can routine and got it wrong.

If good programmers who have just been told some of the big pitfalls can't do it, then why should I expect that anyone else will get it right?

The problem isn't with the maintainance programmer. It is with how a couple of independent features do not combine in any

If someone needs to override can() and does it incorrectly, calling UNIVERSAL::can() will give the wrong answer. You can't fix that without fixing their code. That's their bug.

If someone needs to override can() and does it correctly, calling UNIVERSAL::can() will still give the wrong answer. How is that possibly good? What possible legitimate reason is there for recommending it? This technique has no chance of working correctly in the face of an overridden can()! That's your bug.

I think that I said it fairly well here [perlmonks.org]. From my point of view, can is not to be considered fully trustworthy or reliable. Since I don't consider it reliable, I do not rely on it, and I don't waste much energy worrying about whether I'm breaking it.

By contrast you view it as something that is documented and supposed to work. If someone breaks it, you expect them to fix it. And since you expect people to fix it, you get upset if someone else bypasses that fix.

Somehow, strangely, this was already fixed...maybe I did it
subconsciously, maybe there are helpful little gnomes running around
in the repository and fixing bugs while we sleep, I don't know..
-- Jarkko Hietaniemi

Stories, comments, journals, and other submissions on use Perl; are Copyright 1998-2006, their respective owners.