ti at lemonia.org
Mon Jan 15 21:56:36 GMT 2007
> On Sunday 14 January 2007 15:01, Tim Sweetman wrote:
>>chromatic says (I paraphrase) if you implement AUTOLOAD, but don't
>>implement can, that's a bug, and you're lazy.
> It's lazy in the sense that leaving the gas on may save you having to turn it
> on again ever, in the near future and in a permanent sense.
>>The UNIVERSAL perldoc also says:
>>> "can" can be called as a class (static) method, an object
>>>method, or a function.
> Not the latest versions, which I patched [...]
>>[use] UNIVERSAL::can to push the
>>UNIVERSAL class's can implementation out of the way and do something
>>different (and hopefully better).
> That's not what the UNIVERSAL::can module does.
... That's exactly what it does!
"This module replaces UNIVERSAL::can() with a method that checks..."
> UNIVERSAL::can attempts to protect *working* code from breakage thanks to the
> buggy code of other people
Evidently, the code it "protects" is not "working", otherwise you
wouldn't need UNIVERSAL::can to "protect" it. It makes non-working code
work, by replacing UNIVERSAL::can() with a method that does some other
> , warning copiously that invoking methods as
> functions has the nasty tendency to break working code.
> I suggest you immediately replace all of your constructors in your production
> code with Acme::UNIVERSAL::new for a very quick lesson on the value of
> adhering to superclass interfaces. (If you don't use source control,
> consider it two lessons.)
I completely understand that writing (for example)
my $toast_rack = Toast::Rack->new;
Toast::Rack::put_on_table ($toast_rack, $table);
is incorrect, exactly because any movement around the class hierarchy of
put_on_table will cause the code to stop working.
As I see it, there are at least three schools of thought here:
1. Use AUTOLOAD. UNIVERSAL::can, ->can, and inheritance may then go
wrong, but we don't care, because we're not using those, and
UNIVERSAL::can isn't reliable anyway: it's POD says, you can't rely on
can, because classes may use AUTOLOAD.
2. If you're using AUTOLOAD, you should redefine can, otherwise this is
incorrect/lazy/inconsistent, but expecting UNIVERSAL::can to work as a
function is incorrect and a bug (chromatic's view)
3. AUTOLOAD is a can of worms, and should be avoided wherever possible.
You can work around its problems, but you'd end up with something like
Class::Std's AUTOMETHOD, with reimplementation of UNIVERSAL::can and
support for inheritance. (damian conway's view). (Class::Std does a
similar trick, redefining UNIVERSAL::can).
> adhering to superclass interfaces
UNIVERSAL's documentation is so vague on what you can expect from can
that any fool (school of thought #1) can adhere to it.
(That's unless you decide that you don't like the superclass interface,
and you're going to regard mere adherence to it as being a bug, and
patch the definition of the superclass interface, which is what you did!)
I actually think option 1 is pretty crappy, because having a module
which says it can't, but can, and once it does, admits it can, is just
plain unhelpful. Eventually building AUTOMETHOD, or similar, into the
language, and deprecating AUTOLOAD, would seem to be the way to go, if
anyone cares enough to do it. Something like AUTOMETHOD means you can
declare your autoloaded stuff once, and have can *and* invocation do the
right thing. Expecting programmers to do something twice, when the
effects of only doing it once are obscure and subtle, is not realistic. DRY.
> It seems reasonable to me to expect people writing OO Perl to have some vague
> sense of how methods work.
You're expecting them to see a lurking problem over the horizon; a
problem they may never have thought of, and which may never affect them.
You're then expecting them to come to the same opinion as you (in
contrast to the old version of the UNIVERSAL POD, or Damian Conway), and
to code accordingly.
More information about the london.pm