Re: Test::Aggregate and UNIVERSAL::can

2008-01-03 Thread Aristotle Pagaltzis
* demerphq <[EMAIL PROTECTED]> [2008-01-04 00:00]:
> Consider that with 5.10 its possible to use other method
> resolution rules than the one your snippet mimics.

Does it change the MRO globally without regard for whether any
loaded classes are prepared for that?

Regards,
-- 
Aristotle Pagaltzis // 


Re: Test::Aggregate and UNIVERSAL::can

2008-01-03 Thread demerphq
On 03/01/2008, Aristotle Pagaltzis <[EMAIL PROTECTED]> wrote:
> * Andy Armstrong <[EMAIL PROTECTED]> [2008-01-03 18:25]:
> > On 3 Jan 2008, at 16:55, Ovid wrote:
> >>  my $super = __PACKAGE__->can("SUPER::$sub") or die;
> >>
> >> This is OO code and that should actually read:
> >>
> >>  my $super = __PACKAGE__->can($sub) or die;
> >
> > Should that be __PACKAGE__->SUPER::can($sub) ?
>
> No. That calls `can` from the superclass, but passes
> `__PACKAGE__` as the invocant. Assuming that the subclass and the
> superclass use the same inherited `can` method, the result is
> therefore exactly the same.
>
> The correct incantation is
>
> my ( $super ) = grep { $_->can( $sub ) } @ISA;

I think the correct thing is what kicked off this conversation.

my $sub= __PACKAGE__->can("SUPER::$sub");

Consider that with 5.10 its possible to use other method resolution
rules than the one your snippet mimics.

Yves

-- 
perl -Mre=debug -e "/just|another|perl|hacker/"


Re: Test::Aggregate and UNIVERSAL::can

2008-01-03 Thread Andy Armstrong

On 3 Jan 2008, at 21:02, Aristotle Pagaltzis wrote:

No. That calls `can` from the superclass, but passes
`__PACKAGE__` as the invocant. Assuming that the subclass and the
superclass use the same inherited `can` method, the result is
therefore exactly the same.

The correct incantation is

   my ( $super ) = grep { $_->can( $sub ) } @ISA;



Yes, I realised that as soon as I posted - hence my mini debate with  
myself. Then I went and fixed the dodgy bit of code I'd just written  
that used exactly that idiom :)


--
Andy Armstrong, Hexten






Re: Test::Aggregate and UNIVERSAL::can

2008-01-03 Thread Aristotle Pagaltzis
* Andy Armstrong <[EMAIL PROTECTED]> [2008-01-03 18:25]:
> On 3 Jan 2008, at 16:55, Ovid wrote:
>>  my $super = __PACKAGE__->can("SUPER::$sub") or die;
>>
>> This is OO code and that should actually read:
>>
>>  my $super = __PACKAGE__->can($sub) or die;
>
> Should that be __PACKAGE__->SUPER::can($sub) ?

No. That calls `can` from the superclass, but passes
`__PACKAGE__` as the invocant. Assuming that the subclass and the
superclass use the same inherited `can` method, the result is
therefore exactly the same.

The correct incantation is

my ( $super ) = grep { $_->can( $sub ) } @ISA;

-- 
*AUTOLOAD=*_;sub _{s/(.*)::(.*)/print$2,(",$\/"," ")[defined wantarray]/e;$1}
&Just->another->Perl->hack;
#Aristotle Pagaltzis // 


Re: Test::Aggregate and UNIVERSAL::can

2008-01-03 Thread demerphq
On 03/01/2008, chromatic <[EMAIL PROTECTED]> wrote:
> On Thursday 03 January 2008 09:58:28 demerphq wrote:
>
> > And thinking about it more i think that was the whole point of the
> > weird call, Im guessing here, but probably this code isnt in a method
> > which means that he doesnt have access to SUPER so, he passes it into
> > can() which does.
> >
> > The following one liner demonstrates what the author of
> > Template::Timer was (correctly) doing. Note that it doesnt matter if
> > you define B::foo or not.
> >
> > $ perl -le'@B::ISA=qw(A); sub A::foo {print "in A::foo"} package B;
> > sub foo {print "in B::foo"} __PACKAGE__->can("SUPER::foo")->();'
> > in A::foo
>
> Is that documented anywhere to work?  I couldn't find it.  In fact, it
> contradicts the documentation of can():
>
> "can" checks if the object or class has a method called "METHOD".
> If it does then a reference to the sub is returned. If it does not
> then undef is returned.  This includes methods inherited or
> imported by $obj, "CLASS", or "VAL".

Even if it isnt explicitly documented I take it as being implicitly
documented by the fact that SUPER::  is documented (in perltoot at
least) to have no meaning except inside of a method call. So if you
arent inside of a method call how are you to get access to an objects
overloaded method? And i dont think "you don't" is a good answer as
its clearly useful to do in dynamically constructed classes.

As for the documentation, ive probably been in front of this machine
for too long today so im not seeing the contradiction. Are you basing
this on the bit where it says 'called "METHOD"'?  Personally I dont
think that paragraph goes a long way towards settling things either
way.

OTOH Looking through the sources a bit it looks to me like this is
pretty deliberate behaviour. UNIVERSAL::can() is just a wrapper around
gv_fetchmethod_autoload() which is internally documented to respect
SUPER::.

Also consider the case of $obj->$method(). Unless we want

$method='SUPER::foo';
$obj->can($method)->()

to do something different than

$method='SUPER::foo';
$obj->$method()

I think it has to respect SUPER.

I think when you add up the incidental evidence like things like above
the only rational conclusion is that the native ->can() *is* doing the
right thing.

Yves



-- 
perl -Mre=debug -e "/just|another|perl|hacker/"


Re: Test::Aggregate and UNIVERSAL::can

2008-01-03 Thread chromatic
On Thursday 03 January 2008 09:58:28 demerphq wrote:

> And thinking about it more i think that was the whole point of the
> weird call, Im guessing here, but probably this code isnt in a method
> which means that he doesnt have access to SUPER so, he passes it into
> can() which does.
>
> The following one liner demonstrates what the author of
> Template::Timer was (correctly) doing. Note that it doesnt matter if
> you define B::foo or not.
>
> $ perl -le'@B::ISA=qw(A); sub A::foo {print "in A::foo"} package B;
> sub foo {print "in B::foo"} __PACKAGE__->can("SUPER::foo")->();'
> in A::foo

Is that documented anywhere to work?  I couldn't find it.  In fact, it 
contradicts the documentation of can():

"can" checks if the object or class has a method called "METHOD".
If it does then a reference to the sub is returned. If it does not
then undef is returned.  This includes methods inherited or
imported by $obj, "CLASS", or "VAL".

-- c


Re: Test::Aggregate and UNIVERSAL::can

2008-01-03 Thread demerphq
On 03/01/2008, Andy Armstrong <[EMAIL PROTECTED]> wrote:
> On 3 Jan 2008, at 17:20, Andy Armstrong wrote:
> >> my $super = __PACKAGE__->can($sub) or die;
> >
> > Should that be __PACKAGE__->SUPER::can($sub) ?
>
>
> Hmm. Does that do what I think it does? Maybe not.

Without looking at the code we dont know whether the call is from
within a method call.

And thinking about it more i think that was the whole point of the
weird call, Im guessing here, but probably this code isnt in a method
which means that he doesnt have access to SUPER so, he passes it into
can() which does.

The following one liner demonstrates what the author of
Template::Timer was (correctly) doing. Note that it doesnt matter if
you define B::foo or not.

$ perl -le'@B::ISA=qw(A); sub A::foo {print "in A::foo"} package B;
sub foo {print "in B::foo"} __PACKAGE__->can("SUPER::foo")->();'
in A::foo

So assuming this code was NOT inside a method (most likely as he said
it was part of code that installs methods) it looks like the code that
Ovid bumped into was in fact correct, and chromatic's UNIVERSAL::can
is broken with regard to SUPER::.

> And talking to yourself? What's all that about?

Sometimes its hard to find decent conversation. :-)

cheers,
Yves



-- 
perl -Mre=debug -e "/just|another|perl|hacker/"


Re: Test::Aggregate and UNIVERSAL::can

2008-01-03 Thread demerphq
On 03/01/2008, Ovid <[EMAIL PROTECTED]> wrote:
> --- demerphq <[EMAIL PROTECTED]> wrote:
>
> > > The problem is this line in Template::Timer:
> > >
> > >   my $super = __PACKAGE__->can("SUPER::$sub") or die;
> > >
> > > This is OO code and that should actually read:
> > >
> > >   my $super = __PACKAGE__->can($sub) or die;
> >
> > Er, i dont see how it could. Then $super would have a reference to
> > its own method and not its parents.
>
> I should have posted more context.  What's happening is that
> Template::Timer inherits from Template::Context and that line merely
> checks that two methods which it inherits actually are available.  If
> they are, it wraps them in timing code.  It does *not* implement those
> methods directly so it can't have a reference to its own method.
>
> An alternative would be to do search @ISA or refer to the base class
> directly:
>
>   my $super = Template::Context->can($sub) or die;
>
> That's a bit ugly and not really in the OO spirit, but it also works
> around the fact that it doesn't play well with UNIVERSAL::can.

This is all strange, but now i understand what you mean. Thanx.

Yves


-- 
perl -Mre=debug -e "/just|another|perl|hacker/"


Re: Test::Aggregate and UNIVERSAL::can

2008-01-03 Thread Andy Armstrong

On 3 Jan 2008, at 17:20, Andy Armstrong wrote:

my $super = __PACKAGE__->can($sub) or die;


Should that be __PACKAGE__->SUPER::can($sub) ?



Hmm. Does that do what I think it does? Maybe not.

And talking to yourself? What's all that about?

--
Andy Armstrong, Hexten






Re: Test::Aggregate and UNIVERSAL::can

2008-01-03 Thread Andy Armstrong

On 3 Jan 2008, at 16:55, Ovid wrote:

 my $super = __PACKAGE__->can("SUPER::$sub") or die;

This is OO code and that should actually read:

 my $super = __PACKAGE__->can($sub) or die;


Should that be __PACKAGE__->SUPER::can($sub) ?

--
Andy Armstrong, Hexten






Re: Test::Aggregate and UNIVERSAL::can

2008-01-03 Thread Ovid
--- demerphq <[EMAIL PROTECTED]> wrote:

> > The problem is this line in Template::Timer:
> >
> >   my $super = __PACKAGE__->can("SUPER::$sub") or die;
> >
> > This is OO code and that should actually read:
> >
> >   my $super = __PACKAGE__->can($sub) or die;
> 
> Er, i dont see how it could. Then $super would have a reference to
> its own method and not its parents.

I should have posted more context.  What's happening is that
Template::Timer inherits from Template::Context and that line merely
checks that two methods which it inherits actually are available.  If
they are, it wraps them in timing code.  It does *not* implement those
methods directly so it can't have a reference to its own method.

An alternative would be to do search @ISA or refer to the base class
directly:

  my $super = Template::Context->can($sub) or die;

That's a bit ugly and not really in the OO spirit, but it also works
around the fact that it doesn't play well with UNIVERSAL::can.

Cheers,
Ovid

--
Buy the book  - http://www.oreilly.com/catalog/perlhks/
Perl and CGI  - http://users.easystreet.com/ovid/cgi_course/
Personal blog - http://publius-ovidius.livejournal.com/
Tech blog - http://use.perl.org/~Ovid/journal/


Re: Test::Aggregate and UNIVERSAL::can

2008-01-03 Thread demerphq
On 03/01/2008, Ovid <[EMAIL PROTECTED]> wrote:
> I mentioned that we removed UNIVERSAL::can because of bugs introduced
> by global behavior changes, but to be fair to chromatic, I should
> explain that this is because of code in Template::Timer:
>
>   perl -MUNIVERSAL::can -MTemplate::Timer -e 1
>   Died at lib/perl5/Template/Timer.pm line 63.
>   Compilation failed in require.
>   BEGIN failed--compilation aborted.
>
> The problem is this line in Template::Timer:
>
>   my $super = __PACKAGE__->can("SUPER::$sub") or die;
>
> This is OO code and that should actually read:
>
>   my $super = __PACKAGE__->can($sub) or die;

Er, i dont see how it could. Then $super would have a reference to its
own method and not its parents.

Yves

-- 
perl -Mre=debug -e "/just|another|perl|hacker/"


Re: Test::Aggregate and UNIVERSAL::can

2008-01-03 Thread Ovid
I mentioned that we removed UNIVERSAL::can because of bugs introduced
by global behavior changes, but to be fair to chromatic, I should
explain that this is because of code in Template::Timer:

  perl -MUNIVERSAL::can -MTemplate::Timer -e 1
  Died at lib/perl5/Template/Timer.pm line 63.
  Compilation failed in require.
  BEGIN failed--compilation aborted.

The problem is this line in Template::Timer:

  my $super = __PACKAGE__->can("SUPER::$sub") or die;

This is OO code and that should actually read:

  my $super = __PACKAGE__->can($sub) or die;

That makes the problem go away.  Barring a local fix or the author
fixing this, eliminating UNIVERSAL::can made the problem go away.

David Wheeler reported this problem earlier at
http://rt.cpan.org//Ticket/Display.html?id=16805

Cheers,
Ovid

--
Buy the book  - http://www.oreilly.com/catalog/perlhks/
Perl and CGI  - http://users.easystreet.com/ovid/cgi_course/
Personal blog - http://publius-ovidius.livejournal.com/
Tech blog - http://use.perl.org/~Ovid/journal/