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

Re: [5.8.12] Proposal for changing UNIVERSAL semantics

Thread Previous | Thread Next
Michael G Schwern
November 4, 2003 15:30
Re: [5.8.12] Proposal for changing UNIVERSAL semantics
Message ID:
On Tue, Nov 04, 2003 at 05:35:02AM -0800, Michael Jacob wrote:
> On 2003-11-04 01:08:32 Michael G Schwern <> was overheard saying:
> ---------------------------------------------------
> >	my $code_ref = $class->can('can');
> Add a "use UNIVERSAL qw( :canAsInPerl58 );" to the program that require an old module. Then this will work again and other modules will fail again if there is something unexpected in UNIVERSAL::.

No, backwards compatiblity means you don't have to change in old code for it
to work in new versions.  If we were to do this at all it would be:

	use UNIVERSAL qw( :canAsInPerl510 );

to get the new behavior.  That would fairly guarantee it never got used.

> >Are you saying we can't rely on not being modified... when,
> >at run time?  Sometime in the future?  I don't understand.
> after we put our module to CPAN and some other programmer used it. When Caroll reports the bug to Bob he will be completly puzzled, because ha cannot find any bug in his code...

Umm, this is the same problem with having a bug in *any* code you rely on.

> >Your code examples seem to imply that anything inherited from UNIVERSAL
> >is inherited by mistake and must be covered up.  That runs directly against
> No, it's not inherted by mistake, the test for it returns true (any coderef is true) by mistake. Neither programmer X who write "bar->can('foo')" nor programmer Y who did not write "sub bar::foo" nor programmer Z who wrote "sub UNIVERSAL::foo" expected bar->can() to return true here.

How can you possibly know what they expect?!

Again, the naming clash you describe can happen with *any* code you rely on.
Its possible for *any* module you inherit from to name a method in the same
way as another.

> >the current uses of UNIVERSAL:: on CPAN.  UNIVERSAL::monkier, 
> Doesn't need to can() for. Works without can() just as good.

	# Check to see if the object supports monikers.
	if( $obj->can('moniker') ) {
	    $moniker = $obj->moniker;

Ooops.  And no, I shouldn't be checking for UNIVERSAL->can('moniker')
because that violates encapsulation.  I shouldn't care if the class or
UNIVERSAL implements moniker(), its part of the extended UNIVERSAL interface.

Am I running a risk of clashing with some other interface that uses the
name 'moniker'?  Yes.  This happens any time you depend on method name
being there.  In other cases I might also check $obj->isa('Some::Class')
but there's no point since this moniker is in UNIVERSAL.

Yes, UNIVERSAL is very global and should be used with care.

> >UNIVERSAL::require and 
> Seems to be broken the same way as Sorry.

Read the bloody comment in the code.  When's import is fixed,
UNIVERSAL::require will be fixed.

> >put perfectly normal public methods into UNIVERSAL.
> Yes, that's what I also say. It is ok to add whatever to UNIVERSAL. But, if some programmer asks what object/class X can() he will not expect to find our new methods.

Again, you cannot predict what the programmer expects, especially when its
documented to do that very thing.

> If you put a comment() method into UNIVERSAL you will find it called from XML::SAX while parsing. Huh? That is because XML::SAX looks with can() on its handlers to see if thex are interested on comment() calls. If not, it won't call comment(). But now can() always returns a coderef. And that coderef is not interested to be called by a module that did not know in advance that it is there.

UNIVERSAL should be treated with great care.  Papering over it with can()
isn't going to change this fact.

> >> In future, one who rally want's to catch _soft_referenced_method_calls_ to can(), is() and VERSION() must write:
> >
> >What's a soft_referenced_method_call?
> $y = 'y'; $a = $x->can($y); $x->$y();
> as opposed to real soft references:
> $y = 'y'; $x->$y();

Those two appear to be equivalent.  I think you meant.

$y = 'y';  $a = $x->can($y);  $x->$a();

I wouldn't call it a soft reference, but that doesn't matter.

> and hard references:
> $y = \&x::y; $x->$y();
> and normal method calls:
> $x->y();
> The other 3 can be done always, they don't need can(). So a wanted to make clear that we would only break modules doing a seldom used contruct on one of exactly three method names.

...or anything else that might be put into UNIVERSAL.

> >>   if (my $a = $obj->can($method) || UNIVERSAL->can($method)) {
> >> 
> >> Tell me what more more often will be written as "$obj->can($method)" by accident?
> I don't think so. As I pointed out in above example, the test for a method inherted from UNIVERSAL will usually not be what the programmer wants. Calling that method on the other hand will usually be, but there's no can needed. After the "use UNIVERSAL::modifying::module", we can just call A::B::C->buh() without testing for it first.

Ok, now you're arguing against yourself.  (I didn't write that bit above,
you did).

Michael G Schwern
I sit on the floor and pick my nose
  and think of dirty things
Of deviant dwarfs who suck their toes
  and elves who drub their dings.
	-- Frito Bugger, "Bored Of The Rings"

Thread Previous | Thread Next Perl Programming lists via nntp and http.
Comments to Ask Bjørn Hansen at | Group listing | About