Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why is Perl saying I only use this once? Why is that even an issue?

Tags:

perl

I have some code that I've managed to narrow down to the following smallest-code sample.

First I have a module plugh.pm which is responsible for reading in a configuration file. The meat of this can basically be replaced with the following, which sets up one configuration item:

use strict;
use warnings;
sub cfgRead () { $main::cfg{"abc"} = "/usr"; }
1;

Then I have a main program which uses that module as follows, simply calling the function to set up configuration items, then using one of those items in a subroutine:

#!/usr/bin/env perl

use strict;
use warnings;
use 5.005;

require File::Basename;
import File::Basename "dirname";
push (@INC, dirname ($0));
require plugh;

my (%cfg);

sub subOne () {
        my $list = `ls -1 $main::cfg{"abc"}`;
        my @list = split (/\s+/, $list);
        my $fspec;
        foreach $fspec (@list) {
                print $fspec . "\n";
        }
}

sub mainLine () {
        cfgRead();
        subOne();
}

mainLine();

Now, when I run this, I get the following output with the first line being standard error and the rest being standard output:

Name "main::cfg" used only once: possible typo at /home/xyzzy/bin/xyzzy line 15.
bin
games
include
lib
lib64
local
sbin
share
src

The line it's complaining about is the ls -1 subprocess creation. My question is simply: so what? Yes, I only use it once but why is that even an issue?

If I was never using it, then fine, but I can't see why Perl is warning me about only using it once.

I get the variable from the associative array and then use it to get a directory listing. Is there some sort of bizarre Perl guideline that states variables have to be used at least twice? Seven times? Forty-two? I'm seriously stumped.

like image 512
paxdiablo Avatar asked Nov 28 '22 18:11

paxdiablo


2 Answers

I think your original question is answered, so I'll just pass along my advice. Don't ever use globals if you can avoid it. You are using subroutines as mere clusters of code and not passing them any arguments, and that's where your problems come from.

Module:

sub cfgRead {
    my %cfg;
    $cfg{"abc"} = "/usr";
    ...
    return \%cfg;
}

Main:

sub subOne {
    my $cfg = shift;
    my $list = `ls -1 $cfg->{"abc"}`;
    ....
}

my $cfg = cfgRead();
subOne($cfg);
like image 135
TLP Avatar answered Dec 10 '22 01:12

TLP


There are a few odd things here.

First: when you have use strict active, you will get a warning if you use a variable without declaring it, or referencing it by fully qualified name.

What you have actually done is to declare a local %cfg with my() in xyzzy.pl, and then to reference a different, package-global variable %main::cfg (implicitly declared by using its fully qualified name).

To make the reference link to the same %cfg that you declared, you should declare it our() to make it package-global. Then you can either reference it as $main::cfg{} in both places (or just $cfg{} from xyzzy.pl), or else you can declare it our() in plugh.pm as well (so that you can use the bare %cfg in both places).

The odd thing is that you do have two references to that variable, so you shouldn't get the warning. I think what has happened here is that the implicit declarations in two separate files are assumed to be separate variables.

xyzzy.pl:

require plugh;

our (%cfg);

sub subOne () {
   my $list = `ls -1 $cfg{"abc"}`;
   ...
}

plugh.pm:

our(%cfg);
sub cfgRead () { $cfg{"abc"} = "/usr"; }
like image 20
Russell Zahniser Avatar answered Dec 10 '22 02:12

Russell Zahniser