in reply to Re: Undefined subroutine &main::func1
in thread Undefined subroutine &main::func1 [SOLVED]

What looks most suspicious to me (and perhaps to kcott), are the '&' sigils in your use and %EXPORT_TAGS.

The ampersand is optional, but legal in the exporter variables (@EXPORT and @EXPORT_OK). Quoting Exporter:

How to Export

The arrays @EXPORT and @EXPORT_OK in a module hold lists of symbols that are going to be exported into the users name space by default, or which they can request to be exported, respectively. The symbols can represent functions, scalars, arrays, hashes, or typeglobs. The symbols must be given by full name with the exception that the ampersand in front of a function is optional, e.g.

@EXPORT = qw(afunc $scalar @array); # afunc is a function @EXPORT_OK = qw(&bfunc %hash *typeglob); # explicit prefix on +&bfunc

If you are only exporting function names it is recommended to omit the ampersand, as the implementation is faster this way.

From that, I conclude that the ampersand is optional, but not recommended also in %EXPORT_TAGS and in parameters for import() (i.e. after use and require).

The source code of Exporter actively removes leading ampersands in sub import:

my $exports = \@{"$pkg\::EXPORT"}; # ... my $export_cache = ($Cache{$pkg} ||= {}); my $args = @_ or @_ = @$exports; if ($args and not %$export_cache) { s/^&//, $export_cache->{$_} = 1 foreach (@$exports, @{"$pkg\::EXPORT_OK"}); }

The same logic also exists in Exporter::Heavy:

sub _rebuild_cache { my ($pkg, $exports, $cache) = @_; s/^&// foreach @$exports; @{$cache}{@$exports} = (1) x @$exports; my $ok = \@{"${pkg}::EXPORT_OK"}; if (@$ok) { s/^&// foreach @$ok; @{$cache}{@$ok} = (1) x @$ok; } }

Exporter::Heavy even adds ampersand prefixes sometimes:

sub heavy_export { # ... my($pkg, $callpkg, @imports) = @_; my($type, $sym, $cache_is_current, $oops); my($exports, $export_cache) = (\@{"${pkg}::EXPORT"}, $Exporter::Cache{$pkg} ||= {}); # ... my($fail, $fail_cache) = (\@{"${pkg}::EXPORT_FAIL"}, $Exporter::FailCache{$pkg} ||= {}); if (@$fail) { if (!%$fail_cache) { # Build cache of symbols. Optimise the lookup by adding # barewords twice... both with and without a leading &. # (Technique could be applied to $export_cache at cost of memo +ry) my @expanded = map { /^\w/ ? ($_, '&'.$_) : $_ } @$fail; warn "${pkg}::EXPORT_FAIL cached: @expanded" if $Exporter::Ver +bose; @{$fail_cache}{@expanded} = (1) x @expanded; } my @failed; # ... } # ... }

Alexander

--
Today I will gladly share my knowledge and experience, for there are no sweeter words than "I told you so". ;-)

Replies are listed 'Best First'.
Re^3: Undefined subroutine &main::func1
by soonix (Chancellor) on Jun 28, 2015 at 15:25 UTC

    Ah. I think I mixed that up with the inadvertently-prototype-creating use of '()'. Thank you for the elaborated enlightenment.

    I must admit that I hadn't run the "problematic" code. I just did, and made the following observations.

    1. first, I tried it in the same directory, changing the file name to TestClient.pm and modified package name use statement accordingly.
      The thing worked.
    2. now I created Net and Net//SNTP folders, moved and renamed the .pm file.
    3. After receiving a "can't locate in @INC" message I realized I hadn't correctly moved the module :-)
    4. Now i got the message in the OP! - (although line 8, not 9)
    5. Then it dawned on me: I hadn't changed back the package statement! After correcting this, it worked again.
    So, thanos1983, I bet the module in your post are different from ehat you have on your disc. Check the spelling in your package statement!

Re^3: Undefined subroutine &main::func1
by thanos1983 (Parson) on Jun 28, 2015 at 15:35 UTC

    Hello afoken,

    Thank you for your time and effort reading and replying to my query.

    Well after a lot of experimentation I have concluded that the problem lies with the directories. I am using Net::SNTP::Client.pm which I have install it locally. I assume since the moment that I install it locally since then any modification I am applying on the module is ignored because I can see the installed directory Net-SNTP-Client.

    So I assume that I first need to uninstall the module and then find a way to experiment with the module before installing it.

    I have tried almost 100 different combinations with the use lib '/home/username/ModuleFolder/'; but I keep getting the same error:

    Can't locate Net/SNTP/Client.pm in @INC (you may need to install the N +et::SNTP::Client module) (@INC contains: /home/tinyos/Desktop/Test /h +ome/tinyos/Desktop/Test/ /etc/perl /usr/local/lib/perl/5.18.2 /usr/lo +cal/share/perl/5.18.2 /usr/lib/perl5 /usr/share/perl5 /usr/lib/perl/5 +.18 /usr/share/perl/5.18 /usr/local/lib/site_perl .) at client.pl lin +e 8. BEGIN failed--compilation aborted at client.pl line 8.

    I have unistalled my module since I think this is the root of all problems before I move to the next step I need to find a way to make it work.

    Sample of Module Net::SNTP::Client.pm:

    #!/usr/bin/perl use strict; use warnings; use Exporter; package Net::SNTP::Client; use vars qw($VERSION @ISA @EXPORT @EXPORT_OK %EXPORT_TAGS); $VERSION = 1.00; @ISA = qw(Exporter); @EXPORT = (); @EXPORT_OK = qw(func1 func2); %EXPORT_TAGS = ( DEFAULT => [qw(&func1)], Both => [qw(&func1 &func2)] ); sub func1 { return reverse @_ } sub func2 { return map{ uc }@_ } 1;

    Sample of code for script client.pl:

    #!/usr/bin/perl use strict; use warnings; my @list = qw (J u s t ~ A n o t h e r ~ P e r l ~ H a c k e r !); use lib '/home/username/Desktop/Test'; use Net::SNTP::Client qw(func1); print func1(@list),"\n";
    Seeking for Perl wisdom...on the process of learning...not there...yet!
      • the module names in use and package statement must match exactly (speeling and cAsE) - seems OK in your post
      • the file must be in a subdirectory of one of the @INC directories - find out with the following code:
        use strict; use warnings; my $module = 'Net::SNTP::Client'; # change module name here if necessa +ry (my $file = $module) =~ s!::!/!g ; $file .= '.pm'; print "looking for $file\n"; my $found = 0; for (@INC) { my $look = "$_/$file"; if (-e $look) { print "Hooray! found it: $look\n"; ++$found; } else { print "NOT found: $look\n" } } print "PROBLEM: found $found files instead of 1 (one)\n" if $found != +1;
      • And your sub func1 definition should be within the scope of the package statement (looks OK in your post)
      Update: Ah, you just found it out while I was composing this node :-)