'Why is *main::my_func{CODE}* a coderef when function my_func() is exported but not defined?
I have project where I renamed a Perl module because it had a too generic name and wrote a small compatibility module. I even wrote a test for the compatibility module but it was false positive. Why does this feel so hard to test? How to actually test the existence of the exported function if I can't call it because of side effects?
In my compatibility module I inherited from the new module but didn't import its functions. That wasn't enough, to my surprise. Here I built a minimal example with only 1 package involved:
use strict;
use warnings;
use feature qw(say);
{
package MyPackage;
use parent 'Exporter';
our @EXPORT = qw(foo);
}
MyPackage->import();
say *main::foo{CODE};
say *MyPackage::foo{CODE};
say main->can('foo');
say MyPackage->can('foo');
foo();
(I replaced use MyPackage with MyPackage->import() to make this example work in 1 file.)
The output:
CODE(0x55fa5cf9e750)
CODE(0x55fa5cf9e750)
CODE(0x55fa5cf9e750)
CODE(0x55fa5cf9e750)
Undefined subroutine &MyPackage::foo called at inherit.pl line 16.
This all looks like the function exists but it fails when I try to call it.
This is Perl 5.34.
Update to answer zdim’s qestion: What is the actual issue?
I moved the actual code from OldModule.pm to NewModule.pm (not their real names, of course) and created a new OldModule.pm for compatibility with existing software using that. The actual code provided both package functions via import() as well as class and object methods. So I used use parent 'NewModule' to inherit all of them. I believed this would also inherit package functions. My Test with Test2’s can_ok incorrectly showed that it worked.
Thanks to a bug report from a coworker I learned that this was not enough and found I needed to import the package functions as well.
I can’t simply call the functions in question to test the compatibility package because this is part of a CGI app and the functions actually do database operation or print out stuff to STDOUT and would pollute my TAP output. (Yes, part of my mission is to get rid of CGI, of course.)
package OldPackage;
# ABSTRACT: transitional package for new name NewPackage
use strict;
use warnings;
use NewPackage; # this is the line I added to fix the issue
use Exporter qw(import);
our @EXPORT = @NewPackage::EXPORT; # this line only declared undefined functions
1;
Solution 1:[1]
Exporter, in effect, does something similar to this:
*main::foo = \&MyPackage::foo;
Just like with scalars, arrays and hashes, referencing a sub vivifies the symbol. Specifically, it creates an undefined sub as if you had done sub foo;.
$ perl -M5.010 -e'
\&foo; say *foo{CODE};
sub bar; say *bar{CODE};
'
CODE(0x55da28044470)
CODE(0x55da28073750)
exists(&f) checks if it exists, and defined(&f) checks if it's defined.
$ perl -M5.010 -e'
sub foo { }
sub bar;
for (qw( foo bar baz )) {
say exists( &$_ ) ? "$_ exists" : "$_ doesn\x27t exist";
say defined( &$_ ) ? "$_ is defined" : "$_ isn\x27t defined";
}
'
foo exists
foo is defined
bar exists
bar isn't defined
baz doesn't exist
baz isn't defined
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
| Solution | Source |
|---|---|
| Solution 1 |
