Dave Howorth has asked for the wisdom of the Perl Monks concerning the following question:

When UNIVERSAL::can is applied on a method that has been undefined, it produces a result that looks wrong to me. For example:
#!/usr/bin/perl use strict; use warnings; BEGIN { print "can=", __PACKAGE__->can('fred'), ";\n"; } sub fred { print "fred\n"; } print "can=", __PACKAGE__->can('fred'), ";\n"; fred; undef &fred; print "can=", __PACKAGE__->can('fred'), ";\n"; fred;
produces:
Use of uninitialized value in print at test.pl line 5. can=; can=CODE(0x81199b4); fred can=CODE(0x81199b4); Undefined subroutine &main::fred called at test.pl line 11.
That's all as I expect except the last call of can returns a code address that no longer works, and leads to a run-time error if used. I would have expected can to return undef on that occasion.
Am I looking at this the wrong way, or is can dented?

Replies are listed 'Best First'.
Re: can undefined methods?
by Joost (Canon) on Nov 29, 2004 at 13:08 UTC
      Thanks for that Joost, it solved my problem.

      It's definitely OK to undef a subroutine, according to Prog. Perl anyway.

      To give another key point from the thread not included in the summary, 'can' behaves the way it does so that it can be useful in the presence of AUTOLOAD, but the docs could be improved.
Re: can undefined methods?
by Anonymous Monk on Nov 29, 2004 at 16:05 UTC
    When you make undef &fred you are just declaring that sub fred {} is undefined when is called, but this won't remove the CODE reference from the GLOB *fred. Is like to say that *fred{CODE} can't be executed. This behavior exists because you still can have compiled code that make references to this CODE.

    If you really want to remove the CODE from the memory you should use undef *fred, and you will see that can() wont return the CODE.

    But note that undef *fred will remove from memory all fred symbols, like @fred, $fred, etc... So, you should make something like that to remove the code:

    sub fred { print "FRED>> @_\n" ; } @fred = qw(a b c) ; fred() ; print "ARRAY: @fred\n" ; my $can = __PACKAGE__->can('fred') ; print "can1: $can\n" ; undef_sub('fred') ; my $can = __PACKAGE__->can('fred') ; print "can2: $can\n" ; print "ARRAY: @fred\n" ; sub undef_sub { my $sub = shift ; my $s = *{$sub}{SCALAR} ; my $a = *{$sub}{ARRAY} ; my $h = *{$sub}{HASH} ; undef *{$sub} ; *{$sub} = $s ; *{$sub} = $a ; *{$sub} = $h ; }

    By gmpassos