Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

when does UNIVERSAL::can's cache get cleared?

2 views
Skip to first unread message

Nicholas Clark

unread,
Mar 16, 2004, 5:23:40 PM3/16/04
to perl5-...@perl.org
As I understand it, perl has a method cache, which UNIVERSAL::can hooks into.
Should it be cleared when a method is undefined. ie, is "Can 3" in the
following an error?

$ perl package_cache.pl
Can't 1
Can 2
I'm a Foo
Can 3
Undefined subroutine &Foo::foo called at package_cache.pl line 38.
$ cat package_cache.pl
#!/usr/bin/perl -w
use strict;

package Foo;

sub new {
bless [];
}

package main;

my $code = <<'EOP';

package Foo;

sub foo {
my $self = shift;
print "I'm a $self\n";
}

1;
EOP

my $f = Foo->new;

print Foo->can('foo') ? "Can 1\n" : "Can't 1\n";

eval $code or die $@;

print Foo->can('foo') ? "Can 2\n" : "Can't 2\n";

Foo->foo();

undef &Foo::foo;

print Foo->can('foo') ? "Can 3\n" : "Can't 3\n";

Foo->foo();

__END__


(I'm writing Storable regression tests)

Nicholas Clark

Rafael Garcia-Suarez

unread,
Mar 16, 2004, 7:12:49 PM3/16/04
to Nicholas Clark, perl5-...@perl.org
Nicholas Clark wrote:
>
> As I understand it, perl has a method cache, which UNIVERSAL::can hooks into.
> Should it be cleared when a method is undefined.

Probably, as it's cleared in other places.

So I tried this :

NOT TO BE APPLIED
--- pp.c (revision 3350)
+++ pp.c (working copy)
@@ -797,6 +797,7 @@ PP(pp_undef)
GV* gv = CvGV((CV*)sv);
cv_undef((CV*)sv);
CvGV((CV*)sv) = gv;
+ GvCVGEN(gv) = PL_sub_generation++;
}
break;
case SVt_PVGV:

This solves your problem but this makes t/op/method.t and t/op/exists_sub.t
unhappy.

As a workaround you can undef the glob or delete the stash entry (instead of
undeffing the sub.)

Rafael Garcia-Suarez

unread,
Mar 16, 2004, 7:22:58 PM3/16/04
to perl5-...@perl.org, Nicholas Clark
Rafael Garcia-Suarez wrote:
>
> Nicholas Clark wrote:
> >
> > As I understand it, perl has a method cache, which UNIVERSAL::can hooks into.
> > Should it be cleared when a method is undefined.
>
> Probably, as it's cleared in other places.

I changed my mind.

When you C<undef> a sub, it still C<exists>. So perl is correct here. NOTABUG.

Arthur Bergman

unread,
Mar 17, 2004, 3:29:56 AM3/17/04
to Rafael Garcia-Suarez, Nicholas Clark, perl5-...@perl.org

But what happens when you call it?

Arthur

Rafael Garcia-Suarez

unread,
Mar 17, 2004, 3:41:20 AM3/17/04
to perl5-...@perl.org
Arthur Bergman wrote in perl.perl5.porters :

>> When you C<undef> a sub, it still C<exists>. So perl is correct here.
>> NOTABUG.
>>
>
> But what happens when you call it?

Obviously, a fatal error. (This is all because Perl makes a distinction
between subs that are defined -- they have a CV -- and the ones that
only exist -- they only have a symbol table entry, as when you write a
forward declaration.)

Nicholas Clark

unread,
Mar 17, 2004, 3:41:48 AM3/17/04
to Arthur Bergman, Rafael Garcia-Suarez, perl5-...@perl.org

Fails to find a sub body, tries AUTOLOAD.
The behaviour is consistent with stubbing a sub:

perl -lwe 'sub C {print main->can("foo") ? "Can" : "Can'\''t"}; &C; eval "sub foo; 1" or die $@; &C; &foo;'
Can't
Can
Undefined subroutine &main::foo called at -e line 1.

It's consistent. Not everyone finds it helpful.

Nicholas Clark

Nick Ing-Simmons

unread,
Mar 17, 2004, 4:18:18 AM3/17/04
to ni...@ccl4.org, perl5-...@perl.org
Nicholas Clark <ni...@ccl4.org> writes:
>As I understand it, perl has a method cache, which UNIVERSAL::can hooks into.
>Should it be cleared when a method is undefined.

I think so.
If I recall correctly cache is re-built if 'subgeneration' doesn't match.

>ie, is "Can 3" in the
>following an error?

I think so.

Nick Ing-Simmons

unread,
Mar 17, 2004, 4:21:19 AM3/17/04
to rgarci...@free.fr, Nicholas Clark, perl5-...@perl.org
Rafael Garcia-Suarez <rgarci...@free.fr> writes:
>Nicholas Clark wrote:
>>
>> As I understand it, perl has a method cache, which UNIVERSAL::can hooks into.
>> Should it be cleared when a method is undefined.
>
>Probably, as it's cleared in other places.
>
>So I tried this :
>
>NOT TO BE APPLIED
>--- pp.c (revision 3350)
>+++ pp.c (working copy)
>@@ -797,6 +797,7 @@ PP(pp_undef)
> GV* gv = CvGV((CV*)sv);
> cv_undef((CV*)sv);
> CvGV((CV*)sv) = gv;
>+ GvCVGEN(gv) = PL_sub_generation++;
> }
> break;
> case SVt_PVGV:

I think that all that is needed for cache flush is the
PL_sub_generation++
I don't think you need to mess with the GV.

Nick Ing-Simmons

unread,
Mar 17, 2004, 4:24:17 AM3/17/04
to s...@nanisky.com, Nicholas Clark, perl5-...@perl.org, Rafael Garcia-Suarez

I agree with that now.

>>
>
>But what happens when you call it?

Same as what happens if you predeclare it

sub foo;

But never get round to defining it. Try for AUTOLOAD or give message
Nick C was seeing.


>
>Arthur

Rafael Garcia-Suarez

unread,
Mar 17, 2004, 4:28:25 AM3/17/04
to perl5-...@perl.org
Nick Ing-Simmons wrote in perl.perl5.porters :

>>NOT TO BE APPLIED
>>--- pp.c (revision 3350)
>>+++ pp.c (working copy)
>>@@ -797,6 +797,7 @@ PP(pp_undef)
>> GV* gv = CvGV((CV*)sv);
>> cv_undef((CV*)sv);
>> CvGV((CV*)sv) = gv;
>>+ GvCVGEN(gv) = PL_sub_generation++;
>> }
>> break;
>> case SVt_PVGV:
>
> I think that all that is needed for cache flush is the
> PL_sub_generation++
> I don't think you need to mess with the GV.

For some reason that I've not tried to understand, in Nicholas' test
case, the GvCVGEN was == 0, making the CV effectively un-un-cacheable.

Stas Bekman

unread,
Mar 17, 2004, 1:14:52 PM3/17/04
to Rafael Garcia-Suarez, perl5-...@perl.org

In which case can() is a horribly misleading name. Besides telling you that it
can() not, even though it really can when AUTOLOAD is involved. The following
code (posted earlier in the 'undeffing CV' thread) demonstrates that it's
totally unreliable, since while the function "exists" it has no CV, and
therefore it can not be used, while can() says that it is.

#/tmp/can
use warnings;
sub foo { };
*main::foo = sub { };
undef &main::foo;
my $cv = main->can('foo');
$cv->() if $cv;

% perl /tmp/can
Subroutine main::foo redefined at /tmp/can line 3.
Not a CODE reference at /tmp/can line 6.

Notice that my example's error is different and much more unclear to the end
user than Nick's example that started this thread.

I'd suggest to deprecate can() completely, because it's not reliable. Instead
replace it with has() which just checks the entry, and has_cv() that is really
callable.

__________________________________________________________________
Stas Bekman JAm_pH ------> Just Another mod_perl Hacker
http://stason.org/ mod_perl Guide ---> http://perl.apache.org
mailto:st...@stason.org http://use.perl.org http://apacheweek.com
http://modperlbook.org http://apache.org http://ticketmaster.com

Chip Salzenberg

unread,
Mar 17, 2004, 1:25:37 PM3/17/04
to Stas Bekman, Rafael Garcia-Suarez, perl5-...@perl.org
According to Stas Bekman:

> In which case can() is a horribly misleading name. Besides telling you that
> it can() not, even though it really can when AUTOLOAD is involved.

You're obviously confusing can() with will(). :-)
--
Chip Salzenberg - a.k.a. - <ch...@pobox.com>
"I wanted to play hopscotch with the impenetrable mystery of existence,
but he stepped in a wormhole and had to go in early." // MST3K

Rafael Garcia-Suarez

unread,
Mar 17, 2004, 1:27:05 PM3/17/04
to Stas Bekman, perl5-...@perl.org
Stas Bekman wrote:
>
> Rafael Garcia-Suarez wrote:
> > Arthur Bergman wrote in perl.perl5.porters :
> >
> >>>When you C<undef> a sub, it still C<exists>. So perl is correct here.
> >>>NOTABUG.
> >>>
> >>
> >>But what happens when you call it?
> >
> >
> > Obviously, a fatal error. (This is all because Perl makes a distinction
> > between subs that are defined -- they have a CV -- and the ones that
> > only exist -- they only have a symbol table entry, as when you write a
> > forward declaration.)
>
> In which case can() is a horribly misleading name. Besides telling you that it
> can() not, even though it really can when AUTOLOAD is involved. The following
> code (posted earlier in the 'undeffing CV' thread) demonstrates that it's
> totally unreliable, since while the function "exists" it has no CV, and
> therefore it can not be used, while can() says that it is.

I disagree. can() returning a CODE ref for subs that have only a forward
declaration is a feature, as explained in the UNIVERSAL manpage, which
precisely documents the current behaviour.

You can test the definedness of a method with :

sub f; $f=main->can("f"); print defined &$f

Stas Bekman

unread,
Mar 17, 2004, 2:13:32 PM3/17/04
to Rafael Garcia-Suarez, perl5-...@perl.org

So what's the meaning of can() if it can't? it should be declared() or
exists() then.

Chip Salzenberg

unread,
Mar 17, 2004, 2:20:59 PM3/17/04
to Stas Bekman, Rafael Garcia-Suarez, perl5-...@perl.org
According to Stas Bekman:

> So what's the meaning of can() if it can't? it should be declared() or
> exists() then.

And wantarray should be wantlist and local should be temp, yeah, yeah.

Stas Bekman

unread,
Mar 17, 2004, 2:42:10 PM3/17/04
to Chip Salzenberg, Rafael Garcia-Suarez, perl5-...@perl.org
Chip Salzenberg wrote:
> According to Stas Bekman:
>
>>So what's the meaning of can() if it can't? it should be declared() or
>>exists() then.
>
>
> And wantarray should be wantlist and local should be temp, yeah, yeah.

I fail to see how your sarcasm applies, Chip. What prevents us from adding new
methods that really do what they seem to be saying they are doing?

Dave Mitchell

unread,
Mar 17, 2004, 2:51:27 PM3/17/04
to Stas Bekman, Rafael Garcia-Suarez, perl5-...@perl.org
On Wed, Mar 17, 2004 at 10:14:52AM -0800, Stas Bekman wrote:
> In which case can() is a horribly misleading name. Besides telling you that
> it can() not, even though it really can when AUTOLOAD is involved. The
> following code (posted earlier in the 'undeffing CV' thread) demonstrates
> that it's totally unreliable, since while the function "exists"
> it has no CV, and therefore it can not be used, while can() says that it
^^^^^^^^^^^^

> is.
>
> #/tmp/can
> use warnings;
> sub foo { };
> *main::foo = sub { };
> undef &main::foo;
> my $cv = main->can('foo');
> $cv->() if $cv;
>
> % perl /tmp/can
> Subroutine main::foo redefined at /tmp/can line 3.
> Not a CODE reference at /tmp/can line 6.

This seems to be a common misconception. C<undef &foo> does *not* delete
the CV; the CV still exists, but its pad and optree have been thrown away,
and any attempt to execute it gives an error.
It's comparable with C<$foo ="abc"; undef $foo>: $foo still exists as a
PV, but its SvPVX is null, and any attempt to use it gives an error (well,
a warning anyway).

$ perl583 -MDevel::Peek -e 'sub f{}; undef &f; Dump(\&f)'
SV = RV(0x818d048) at 0x8185458
REFCNT = 1
FLAGS = (TEMP,ROK)
RV = 0x818544c
SV = PVCV(0x8180f40) at 0x818544c
REFCNT = 2
FLAGS = ()
IV = 0
NV = 0
COMP_STASH = 0x8175a28 "main"
START = 0x8185b50 ===> 14385
ROOT = 0x0
XSUB = 0x0
XSUBANY = 0
GVGV::GV = 0x81854c4 "main" :: "f"
FILE = "-e"
DEPTH = 0
FLAGS = 0x0
OUTSIDE_SEQ = 91
PADLIST = 0x0
OUTSIDE = 0x8175c68 (MAIN)

--
Standards (n). Battle insignia or tribal totems.

Tim Bunce

unread,
Mar 17, 2004, 3:38:35 PM3/17/04
to Stas Bekman, Chip Salzenberg, Rafael Garcia-Suarez, perl5-...@perl.org
On Wed, Mar 17, 2004 at 11:42:10AM -0800, Stas Bekman wrote:
> Chip Salzenberg wrote:
> >According to Stas Bekman:
> >
> >>So what's the meaning of can() if it can't? it should be declared() or
> >>exists() then.
> >
> >
> >And wantarray should be wantlist and local should be temp, yeah, yeah.
>
> I fail to see how your sarcasm applies, Chip. What prevents us from adding
> new methods that really do what they seem to be saying they are doing?

AUTOLOAD is meant to be transparent.

From the AutoLoader docs:

Subroutine Stubs

In order for object method lookup and/or prototype checking to operate
correctly even when methods have not yet been defined it is necessary
to "forward declare" each subroutine (as in sub NAME;). See the
section on SYNOPSIS in the perlsub manpage. Such forward declaration
creates "subroutine stubs", which are place holders with no code.

I want $foo->can("bark") to be true even if the back() method hasn't been loaded yet.

Tim.

Chip Salzenberg

unread,
Mar 17, 2004, 3:45:04 PM3/17/04
to Stas Bekman, Rafael Garcia-Suarez, perl5-...@perl.org
According to Stas Bekman:

> Chip Salzenberg wrote:
> >According to Stas Bekman:
> >>So what's the meaning of can() if it can't? it should be declared() or
> >>exists() then.
> >
> >And wantarray should be wantlist and local should be temp, yeah, yeah.
>
> I fail to see how your sarcasm applies, Chip. What prevents us from adding
> new methods that really do what they seem to be saying they are doing?

Why, nothing prevents us, of course. But just because something can()
be done doesn't mean it will(), or should().

First, I see no particular benefit to Perl in creating what is
basically an additional alias for a facility that, for reasons of
backward compatibility, needs to remain in place forever anyway.
It's not a renovation if you leave the old construction in place.

Second, for most cases, can() actually does return the right answers.
Do you think that functional stubs just appear out of nowhere? Of
course not. In point of fact, function stubs almost always serve as
markers for functions that *will* be AUTOLOADed on demand, so the
boolean true answer from can() is entirely correct.

I observe that you're trying to make subroutines go away entirely
after the're already defined. Well, that's just dandy, but it's not
what C<undef &func> does, and for reasons of backward compatibility,
it never will be. If you feel like you must invent something, why not
invent Death, Destroyer of Subroutines? That would be new *and* useful.

Brent "Dax" Royal-Gordon

unread,
Mar 17, 2004, 4:22:30 PM3/17/04
to Chip Salzenberg, Stas Bekman, Rafael Garcia-Suarez, perl5-...@perl.org
Chip Salzenberg wrote:
> I observe that you're trying to make subroutines go away entirely
> after the're already defined. Well, that's just dandy, but it's not
> what C<undef &func> does, and for reasons of backward compatibility,
> it never will be. If you feel like you must invent something, why not
> invent Death, Destroyer of Subroutines? That would be new *and* useful.

Candidate:

C:\>perl -e "sub foo {} delete &foo"
delete argument is not a HASH or ARRAY element or slice at -e line 1.

This also fits nicely with the existing meaning of undef vs. delete.

--
Brent "Dax" Royal-Gordon <br...@brentdax.com>
Perl and Parrot hacker

Oceania has always been at war with Eastasia.

Chip Salzenberg

unread,
Mar 17, 2004, 4:38:20 PM3/17/04
to Stas Bekman, Rafael Garcia-Suarez, perl5-...@perl.org
According to Stas Bekman:
> my $cv = foo->can('bar');
> $cv->(@args) if $cv;
>
> So may be the manpage should mention that the above code is bogus and
> suggest the right way to write it?

But my point is that it's *not* bogus in the presence of AUTOLOAD:

package StasExampleClass;
sub bar; # stub so can() returns true
sub AUTOLOAD {
if (substr($AUTOLOAD, rindex($AUTOLOAD, ':')+1) eq 'bar') {
*bar = sub { something_interesting };
goto &bar;
}
}

(BTW, I just realized that the substr/rindex hack above avoids a
regex, which would reset $1 etc, and would therefore interfere with
passing $1 as a parameter. >>bag_o_tricks)

> > If you feel like you must invent something, why not
> > invent Death, Destroyer of Subroutines? That would be new *and* useful.
>

> Unfortunately I don't understand enough internals to write one. Do you?

Is this a trick question? :-)

Stas Bekman

unread,
Mar 17, 2004, 4:20:28 PM3/17/04
to Chip Salzenberg, Rafael Garcia-Suarez, perl5-...@perl.org
Chip Salzenberg wrote:
> According to Stas Bekman:
>
>>Chip Salzenberg wrote:
>>
>>>According to Stas Bekman:
>>>
>>>>So what's the meaning of can() if it can't? it should be declared() or
>>>>exists() then.
>>>
>>>And wantarray should be wantlist and local should be temp, yeah, yeah.
>>
>>I fail to see how your sarcasm applies, Chip. What prevents us from adding
>>new methods that really do what they seem to be saying they are doing?
>
>
> Why, nothing prevents us, of course. But just because something can()
> be done doesn't mean it will(), or should().

I like that explanation. My guess is that many others use can() to populate a
ref to a sub:

my $cv = foo->can('bar');
$cv->(@args) if $cv;

So may be the manpage should mention that the above code is bogus and suggest
the right way to write it?

> First, I see no particular benefit to Perl in creating what is


> basically an additional alias for a facility that, for reasons of
> backward compatibility, needs to remain in place forever anyway.
> It's not a renovation if you leave the old construction in place.
>
> Second, for most cases, can() actually does return the right answers.
> Do you think that functional stubs just appear out of nowhere? Of
> course not. In point of fact, function stubs almost always serve as
> markers for functions that *will* be AUTOLOADed on demand, so the
> boolean true answer from can() is entirely correct.

Agreed.

> I observe that you're trying to make subroutines go away entirely
> after the're already defined. Well, that's just dandy, but it's not
> what C<undef &func> does, and for reasons of backward compatibility,
> it never will be. If you feel like you must invent something, why not
> invent Death, Destroyer of Subroutines? That would be new *and* useful.

Unfortunately I don't understand enough internals to write one. Do you?

__________________________________________________________________

Rafael Garcia-Suarez

unread,
Mar 17, 2004, 4:26:39 PM3/17/04
to Brent "Dax" Royal-Gordon, Chip Salzenberg, Stas Bekman, perl5-...@perl.org
Brent "Dax" Royal-Gordon wrote:
>
> Chip Salzenberg wrote:
> > I observe that you're trying to make subroutines go away entirely
> > after the're already defined. Well, that's just dandy, but it's not
> > what C<undef &func> does, and for reasons of backward compatibility,
> > it never will be. If you feel like you must invent something, why not
> > invent Death, Destroyer of Subroutines? That would be new *and* useful.
>
> Candidate:
>
> C:\>perl -e "sub foo {} delete &foo"
> delete argument is not a HASH or ARRAY element or slice at -e line 1.
>
> This also fits nicely with the existing meaning of undef vs. delete.

And exists accepts a &foo argument. So that's consistent here as well.
(Currently you delete $::{'foo'} to kill the subroutine.)

Chip Salzenberg

unread,
Mar 17, 2004, 4:38:49 PM3/17/04
to Brent Dax Royal-Gordon, Stas Bekman, Rafael Garcia-Suarez, perl5-...@perl.org
According to Brent Dax Royal-Gordon:

> "delete &foo"
> delete argument is not a HASH or ARRAY element or slice at -e line 1.

Yes, I tried that a couple weeks ago and was surprised it didn't work.
>>TODO

Chip Salzenberg

unread,
Mar 17, 2004, 5:42:41 PM3/17/04
to Stas Bekman, Rafael Garcia-Suarez, perl5-...@perl.org
According to Stas Bekman:
> Chip Salzenberg wrote:
> >But my point is that it's *not* bogus in the presence of AUTOLOAD.
>
> But how do you know if there is AUTOLOAD *and* that it'll handle that
> particular sub.

One of my pet peeves is code demanding predictions of the future.
"Will I be able to open the file? Will I be able to call the method?
And what about Naomi? Perspiring minds want to know!"

The right approach is, of course: *Try* it, and see if it works. In
the case of a file, just *open* it and check the return value and $!.
In the case of a method, if you're not sure whether the method is
really there, just *call* it in an eval block and check the return
value and $@.

my $ret = eval { $obj->foo };
if ($@ =~ /^Can't locate \w+ method "foo"/) {
# well, I guess it's not there

Stas Bekman

unread,
Mar 17, 2004, 5:25:44 PM3/17/04
to Chip Salzenberg, Rafael Garcia-Suarez, perl5-...@perl.org
Chip Salzenberg wrote:
> According to Stas Bekman:
>
>>my $cv = foo->can('bar');
>>$cv->(@args) if $cv;
>>
>>So may be the manpage should mention that the above code is bogus and
>>suggest the right way to write it?
>
>
> But my point is that it's *not* bogus in the presence of AUTOLOAD:
>
> package StasExampleClass;
> sub bar; # stub so can() returns true
> sub AUTOLOAD {
> if (substr($AUTOLOAD, rindex($AUTOLOAD, ':')+1) eq 'bar') {
> *bar = sub { something_interesting };
> goto &bar;
> }
> }
>
> (BTW, I just realized that the substr/rindex hack above avoids a
> regex, which would reset $1 etc, and would therefore interfere with
> passing $1 as a parameter. >>bag_o_tricks)

But how do you know if there is AUTOLOAD *and* that it'll handle that
particular sub.

I guess, i shouldn't have called it "bogus", but "not necessarily work" or
"not necessarily DWIM".

>>>If you feel like you must invent something, why not
>>>invent Death, Destroyer of Subroutines? That would be new *and* useful.
>>
>>Unfortunately I don't understand enough internals to write one. Do you?
>
>
> Is this a trick question? :-)

Sort of. If you know how to write a Death, Destroyer of Subroutines, that
would be great if you could write it.

Chromatic

unread,
Mar 17, 2004, 5:47:23 PM3/17/04
to Stas Bekman, perl5-...@perl.org
On Wed, 2004-03-17 at 14:25, Stas Bekman wrote:

> But how do you know if there is AUTOLOAD *and* that it'll handle that
> particular sub.

If the coder were reasonably competent, predeclaring the subroutine
should be a good guide.

I've always understood can() and declarations to make this sort of thing
possible:

#! perl -w

use strict;
use vars '$AUTOLOAD';

use Test::More tests => 2;

sub foo;

sub AUTOLOAD
{

if (substr($AUTOLOAD, rindex($AUTOLOAD, ':')+1)
eq 'foo')
{
*foo = sub { 'called foo' };
goto &foo;
}
}

can_ok( 'main', 'foo' );
my $foo = main->can( 'foo' );
is( $foo->(), 'called foo',
'can() should return subref populatable by AUTOLOAD' );

-- c

Chip Salzenberg

unread,
Mar 18, 2004, 2:37:59 PM3/18/04
to Elizabeth Mattijsen, Stas Bekman, Rafael Garcia-Suarez, perl5-...@perl.org
According to Elizabeth Mattijsen:
> sub foo { system 'something evil' }
>
> I don't think trying to execute a sub is the right way to find out
> whether it exists...

You're missing the point. DO NOT ASK whether the function will work.
That question has no answer. Behold UNIVERSAL::AUTOLOAD and despair.

Instead, arrange your code to simply call the function *when* it is
needed (not before). If, when you call it, it turns out not to be
there, *then* you can note the error and/or try some error recovery.

Elizabeth Mattijsen

unread,
Mar 18, 2004, 2:23:34 PM3/18/04
to Chip Salzenberg, Stas Bekman, Rafael Garcia-Suarez, perl5-...@perl.org
At 17:42 -0500 3/17/04, Chip Salzenberg wrote:
>According to Stas Bekman:
>> Chip Salzenberg wrote:
>> >But my point is that it's *not* bogus in the presence of AUTOLOAD.
>>
>> But how do you know if there is AUTOLOAD *and* that it'll handle that
>> particular sub.
>
>One of my pet peeves is code demanding predictions of the future.
>"Will I be able to open the file? Will I be able to call the method?
>And what about Naomi? Perspiring minds want to know!"
>
>The right approach is, of course: *Try* it, and see if it works. In
>the case of a file, just *open* it and check the return value and $!.
>In the case of a method, if you're not sure whether the method is
>really there, just *call* it in an eval block and check the return
>value and $@.
>
> my $ret = eval { $obj->foo };
> if ($@ =~ /^Can't locate \w+ method "foo"/) {
> # well, I guess it's not there
> }

Hmmm...

sub foo { system 'something evil' }

I don't think trying to execute a sub is the right way to find out
whether it exists...


Liz

Elizabeth Mattijsen

unread,
Mar 18, 2004, 2:51:57 PM3/18/04
to Chip Salzenberg, Stas Bekman, Rafael Garcia-Suarez, perl5-...@perl.org
At 14:37 -0500 3/18/04, Chip Salzenberg wrote:
>According to Elizabeth Mattijsen:
>> sub foo { system 'something evil' }
>>
>> I don't think trying to execute a sub is the right way to find out
>> whether it exists...
>
>You're missing the point. DO NOT ASK whether the function will work.
>That question has no answer. Behold UNIVERSAL::AUTOLOAD and despair.
>
>Instead, arrange your code to simply call the function *when* it is
>needed (not before). If, when you call it, it turns out not to be
>there, *then* you can note the error and/or try some error recovery.

That intent was not clear to me from your message. It is now.


Liz

Chip Salzenberg

unread,
Mar 18, 2004, 3:15:40 PM3/18/04
to Orton, Yves, Elizabeth Mattijsen, Stas Bekman, Rafael Garcia-Suarez, perl5-...@perl.org
According to Orton, Yves:

> >Instead, arrange your code to simply call the function *when* it is
> >needed (not before). If, when you call it, it turns out not to be
> >there, *then* you can note the error and/or try some error recovery.
>
> Shouldn't this be documented?

It is. Quoting 'perldoc UNIVERSAL':

"can" cannot know whether an object will be able to provide a method
through AUTOLOAD, so a return value of undef does not necessarily mean
the object will not be able to handle the method call.

It goes on to explain the stub technique, which is, however, beside
the point of your question:

To get around this some module authors use a forward declaration (see
perlsub) for methods they will handle via AUTOLOAD. For such 'dummy'
subs, "can" will still return a code reference, which, when called,
will fall through to the AUTOLOAD.

Yves Orton

unread,
Mar 18, 2004, 3:09:57 PM3/18/04
to Elizabeth Mattijsen, Chip Salzenberg, Stas Bekman, Rafael Garcia-Suarez, perl5-...@perl.org
>> I don't think trying to execute a sub is the right way to find out
>> whether it exists...
>
>You're missing the point. DO NOT ASK whether the function will work.
>That question has no answer. Behold UNIVERSAL::AUTOLOAD and despair.
>
>Instead, arrange your code to simply call the function *when* it is
>needed (not before). If, when you call it, it turns out not to be
>there, *then* you can note the error and/or try some error recovery.

Shouldn't this be documented?

Yves

James Mastros

unread,
Mar 18, 2004, 3:32:34 AM3/18/04
to perl5-...@perl.org
Rafael Garcia-Suarez wrote:
> And exists accepts a &foo argument. So that's consistent here as well.
> (Currently you delete $::{'foo'} to kill the subroutine.)
(And any $foo, %foo, @foo, *foo{'IO'}, or *foo{'FORMAT'} that happens to
exist (the package global versions of the first three, of course.))

Should delete *foo{TYPE} in general work? I'd really hate to add to the
places where &foo means "the sub named foo" and not "call foo, ignoring
prototypes and not creating a fresh @_". (OTOH, the existing variants
of delete are $foo{bar}, not \$foo{bar}.)

-=- James Mastros
(Hoping he's not in over his head again.)

Tim Bunce

unread,
Mar 19, 2004, 12:37:06 PM3/19/04
to Chip Salzenberg, Orton, Yves, Elizabeth Mattijsen, Stas Bekman, Rafael Garcia-Suarez, perl5-...@perl.org
On Thu, Mar 18, 2004 at 03:15:40PM -0500, Chip Salzenberg wrote:
> According to Orton, Yves:
> > >Instead, arrange your code to simply call the function *when* it is
> > >needed (not before). If, when you call it, it turns out not to be
> > >there, *then* you can note the error and/or try some error recovery.
> >
> > Shouldn't this be documented?
>
> It is. Quoting 'perldoc UNIVERSAL':
>
> "can" cannot know whether an object will be able to provide a method
> through AUTOLOAD, so a return value of undef does not necessarily mean
> the object will not be able to handle the method call.
>
> It goes on to explain the stub technique, which is, however, beside
> the point of your question:
>
> To get around this some module authors use a forward declaration (see
> perlsub) for methods they will handle via AUTOLOAD. For such 'dummy'
> subs, "can" will still return a code reference, which, when called,
> will fall through to the AUTOLOAD.

That wording ought to be stronger. Without stubs inheritance won't
do the right thing. The AutoLoader docs say it better:

Subroutine Stubs

In order for object method lookup and/or prototype checking to operate
correctly even when methods have not yet been defined it is necessary

to "forward declare" each subroutine (as in "sub NAME;"). See "SYNOP-
SIS" in perlsub. Such forward declaration creates "subroutine stubs",


which are place holders with no code.

Tim.

0 new messages