develooper Front page | perl.perl5.porters | Postings from November 2003

Re: [5.12.0] Proposal for changing UNIVERSAL semantics

Thread Previous | Thread Next
From:
Michael Jacob
Date:
November 4, 2003 06:39
Subject:
Re: [5.12.0] Proposal for changing UNIVERSAL semantics
Message ID:
GMail.1067956746.421169564.0425414695@smtp.youvegotpost.com
On 2003-11-04 14:13:16 Michael G Schwern <schwern@pobox.com> was overheard saying:
---------------------------------------------------
> On Tue, Nov 04, 2003 at 04:10:58AM -0800, Michael Jacob wrote:

> [DBI]

Oh why did I choose DBI as an example... Read it with XML::SAX...

>This is directly contrary to how OO inheritence works in Perl.
>Anytime you inherit from a class in Perl you inherit *everything*.
>This is a consequence of not having real method privacy, but that's a
>Perl design decision.  We deal.  UNIVERSAL is simply a special case of this.
>You can just as easily accidentally pick up an AUTOLOAD from Exporter
>as from UNIVERSAL.  Should can() stop looking at Exporter?

There's small difference. When I pick up an AUTOLOAD from Exporter, the _I_ picked it up and _my_ test cases will fail. If if picked it up via UNIVERSAL, that someone other broke my code by remote action and the programs that use my code will fail.

>You seem to consider that anything which is inherited from UNIVERSAL is a
>mistake.  While its true that its all too easy for a lot of accidental

No, I consider can() reporting it a mistake. That's a difference.

>intention.  Again, I point to the three modules on CPAN which put
>public methods into UNIVERSAL.  UNIVERSAL::require, UNIVERSAL::exports and
>UNIVERSAL::moniker.

Seems we a double discussion here. See my last mail.

>> If one wants to add e.g. AUTOLOAD functionality to some class, he would surely not install UNIVERSAL::AUTOLOAD but subclass that class. (And if he doesn't we can tell him he's coding some kind of dangerous rubish. <smile/>)
>
>There's three reasons people use UNIVERSAL::AUTOLOAD.
>
>1) They need universal autoloading.

1a) The need universal autoloading for their modules
1b) They think they universal autoloading for all modules from CPAN

>2) They think they universal autoloading.
>3) They don't understand autoloading.
>
>#1 implies a legit use of UNIVERSAL and shouldn't be papered over.  2 and 3
>are poor design decisions and should be fixed.  Unfortunately, we can't
>programmaticly tell the difference between them.

Do you really think a UNIVERSAL::AUTOLOAD installed by Alice could autoload a missing method in Bobs code?

>UNIVERSAL is an exception *only that it sits at the top of the class
>hierarchy* otherwise its a perfectly normal class.  Methods in it should
>be picked up by can() same as any other.

No, it does NOT sit at the base. It is searched just before giving up, in addition to first searching the full inheritance tree.

Consider this:

sub UNIVERSAL::go { print "U" }
sub b::go { print "A" }
@c::ISA = qw( a b );
c->go();

would print "A" because UNIVERSAL is not the base class of a. Add @a::ISA=qw(UNIVERSAL) and it will print "U".

It is an exeption.

>The whole point of OO is that subclasses act like their parents.  UNIVERSAL
>is the parent of everything.  Again, you might not like it but that's the
>way it is.

And another point is, that changing of a superclass will usually break the subclass. With UNIVERSAL we allow this at runtime. Whow.

>> $class->foo if $class->can('foo') and $class->can('foo') ne UNIVERSAL->can('foo');
>
>Again, you have this idea that anything inherited from UNIVERSAL is garbage.
>This is wrong.

As I said before, why do you expect that UNIVERSAL's method can do the job? I wouldn't trust in that idea unless I had it designed into these classes myself.

>Heh.  "Well, we've got the hood open to change the air filter, why don't we 
>just convert to hydrogen fuel cells while we're at it?"

"Well, we've got the hood open to change the air filter, why don't we check refill oil and water while we're at it?"

When I bring my car to the garage, I let the mechanics do everything needed at once. Ok, we can discuss if a default AUTOLOAD is needed, no problem as this is independent of the can() problem.

up that save way to do it. Else it's just another nearly unused module like that slurp thing last week...
>
>Now you're saying that if you put something on CPAN it'll be unused?  Grand!

No, I'm saying that anything on CPAN that implements something every programmer will do on its own will be unused.

Nobody will ever install a module that just implements a max() function. Nobody will ever have the idea to look for it on CPAN, because everyone has his own sub max{$_[0]>$_[1]?$_[0]:$_[1]} writen out in 10 seconds.

People will not look for modules that solve problems they don't have. They will just write "package UNIVERSAL; sub AUTOLOAD {..." and never think about another module doing the same.

>Placing something in the core doesn't guarantee anyone will use it either.

That's true. People also write "system("rm $a || echo 'Error in rm'")"...

>Let's see... File::stat, Time::Localtime, SelectSaver, FileCache.  Great
>ideas, but for whatever reason nobody uses them.

File::stat is not used, because the perlfunc/stat POD has the stat() example so handy. Time::Localtime is used heavily. SelectSaver, FileCache---never heard about them. What must I do to find them? ls -lR?

>Always remember this:  Once something is in the core *it cannot be removed*.

It can. But it takes two major versions with "deprecated" warnings.

>> Let's express it this way: UNIVERSAL::AUTOLOAD is a limited resource inside core Perl. So a solution for coordinated use should exist in the core, too.
>
>Prove the concept on CPAN first.  There's no need to special case your
>solution by putting it into the core.  Find the users of UNIVERSAL::AUTOLOAD
>and submit them patches for your new module.  I'm sure they'll be
>more than happy that their modules don't conflict with anyone else.

Ok, I'll try to find some time somewhere...

>> >> 5.) Implement a smart UNIVERSAL::import in UNIVERSAL.pm
>> 
>> >This issue has been fixed in bleadperl.
>> 
>>proposed a more compatible way to do it.
>
>You propose to break the documented behavior of can() and say its 
>more compatible than fixing an old bug?  Come now.

Stop, this sentence was meant ONLY for section 5!

>Fortunately, only one person has to have that knowledge and its fixed for
>everyone:  The person who fixes Attribute::Handlers and/or DBI.

And what when Alice::A and Bob::B clash? and 2 years later with Carrol::C and Martha::M?

>> >I didn't hear anything about Net::SSH.
>> 
>> It used use() parameters in a cosmetic way for it's submodules and was no Exporter. Broke on UNIVERSAL::import...
>
>I don't see how that could be, it inherits from Exporter and has no
>custom import.  Are you sure you mean Net::SSH and not something else?

It did NOT inherit from Exporter itself. It was coded with that fact in mind, so it broke when it inherited from Exporter in my system via UNIVERSAL...

>> >>  * existance of UNIVERSAL::AUTOLOAD breaking XML::SAX, ...
>> >
>> >Haven't heard about this one, but I'm not surprised.
>> 
>>  elsif (defined $callbacks->{'Handler'} and $method = $callbacks->{'Handler'}->can('comment') ) {
>>  ...
>>  elsif (defined $callbacks->{'Handler'} and $callbacks->{'Handler'}->can('AUTOLOAD') ) {

>I can tell you right now what's wrong with the logic in XML::SAX::Base.  
>Forget UNIVERSAL::AUTOLOAD, the idea that "its got an AUTOLOAD so it must 
>be able to do what I want" isn't gonna fly.  You don't know what an AUTOLOAD
>might do or what its there for.  *Especially* in a base class like
>XML::SAX::Base where you don't know who's going to extend it or how.

And you don't know what the exeption text might look like that you'll catch below.

No, you've got a class that says it implements some handler interface. This class can either:

* implement all methods, ok

* implement some methods, ok---if the unimplented can() false

* implement some methods and AUTOLOAD, ok but then its AUTOLOAD must know how to cope with all methods

>        elsif( $obj->can('AUTOLOAD') ) {
>	    # hmm, its got an AUTOLOADer, lets see if it does what I need
>	    eval { $obj->some_method };
>	    if( $@ ) {
>                if( $@ =~ /^Can't locate object method "some_method"/ ) {
>		    # guess it doesn't have it, move on.
>		}

Oh? What's that? "The handler we should use has a bug? Whatever; ignore it and go on."

No, the original code is completely right. The handler implements AUTOLOAD, so it must be able to handle all methods in the interface.

Michael 
--
Gratuitous Advertisements:

This email was brought to you by You've Got Post!
http://www.youvegotpost.com

--

Publish your company's press releases for just $5.99 per month (unlimited access), visit http://www.officialspin.com


Thread Previous | Thread Next


nntp.perl.org: Perl Programming lists via nntp and http.
Comments to Ask Bjørn Hansen at ask@perl.org | Group listing | About