paxdiablo
paxdiablo

Reputation: 881093

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

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.

Upvotes: 5

Views: 4295

Answers (3)

TLP
TLP

Reputation: 67900

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);

Upvotes: 12

Russell Zahniser
Russell Zahniser

Reputation: 16354

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"; }

Upvotes: 9

Wes Hardaker
Wes Hardaker

Reputation: 22252

It's simply a helpful comment, because it's pretty unusual to store data in something but never look in it again. Lets look at a more helpful example instead:

use warnings;
$something = 1;
$something = $something + 1;

That, of course, works great as you'd expect. But consider a mistake:

use warnings;
$something = 1;
$something = $somehting + 1;

If you didn't look closely you wouldn't notice the spelling mistake and probably wouldn't figure out why the final value was wrong (since $somehting would be effectively 0).

In this case the warning:

Name "main::somehting" used only once: possible typo at tmp.pl line 3.

Is much more useful. It shows you a possible typo.

(use strict; would be even better in here, of course)

Upvotes: 7

Related Questions