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

What looks most suspicious to me (and perhaps to kcott), are the '&' sigils in your use and %EXPORT_TAGS. I'd try by removing them.

Replies are listed 'Best First'.
Re^2: Undefined subroutine &main::func1
by afoken (Chancellor) on Jun 28, 2015 at 14:29 UTC
    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". ;-)

      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!

      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 :-)
Re^2: Undefined subroutine &main::func1
by thanos1983 (Parson) on Jun 28, 2015 at 14:28 UTC

    Hello soonix,

    Thank you for your time and effort reading and reviewing my code.

    Well if I am not mistaken (I am not really sure since I have no experience with reusable modules) that the '&' is not affecting the code on %EXPORT_TAGS because I am not using them, not yet at least.

    Based on the example Simple Module Tutorial the author is using these sigils and they work fine, I just tested it. I assume the error comes from the Directories that I using Net::SNTP:Client.pm can not be used without been installed.

    Or maybe I am doing many wrong assumptions.

    Any way I am still working on it to learn more about it, thank you for your time and effort again.

    Seeking for Perl wisdom...on the process of learning...not there...yet!

        Hello soonix,

        OMG I just figure it out. Not knowing something can lead to so many mistakes and disappointment!

        You are absolutely right, The way that I define my folders on my module was completely wrong! I had named a module literally Net::SNTP::Client.pm although that I read that when the module will be installed this will mean that will be in the directory Net/SNTP/Client I completely forgot about it and proceed with naming the module like this.

        Of course when loading the module it was not able to see the directory since they do not match. So I simply used the use lib '/home/username/Desktop/Test/'; before loading my module and modified also the directories accordingly. I had to rename my module to Client.pm instead of Net::SNTP::Client.pm and voilą!

        Sample of modified code for simplicity:

        #!/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/'; # note here use Net::SNTP::Client qw(&func1); print func1(@list),"\n";

        Expected output:

        !rekcaH~lreP~rehtonA~tsuJ

        Apologies for not able to understand and explain my problem properly. I have confused too many people that tried to help me.

        Seeking for Perl wisdom...on the process of learning...not there...yet!