http://qs321.pair.com?node_id=655417

Flubb has asked for the wisdom of the Perl Monks concerning the following question:

Hullo Monkees,
My search-fu is weak because I can only find 1 reference to this problem anywhere. I want to check @ARGV, and depending what has been written there, alter a variable:
#!/usr/local/bin/perl -w use strict; my($target, $cust, $cotime) = @ARGV; if ($ARGV[1] eq '-SMC') {$cust eq "SMC";} elsif ($ARGV[1] eq '-FET') {$cust eq 'FET';} elsif ($ARGV[1] eq '-China') {$cust eq 'China';} elsif ($ARGV[1] eq '-SBM') {$cust eq 'SBM';} print "$cust\n";

Running the program (command line is "arg.pl -arm -fet -10:00") produces: "Useless use of string eq in void context at ... line 5" for each line. So a number of questions:
1. Why is this a useless use?
2. What is a void context?
3. What can I do to do this better?
If you can pitch the answer at "humanities graduate" level, I will love you and bear your children.
Thanks :)

Replies are listed 'Best First'.
Re: Useless use of string eq
by Fletch (Bishop) on Dec 06, 2007 at 14:37 UTC

    The eq operator is for comparing strings. Using it in a context other than a comparison (like you've done correctly with your if and elsifs there) doesn't make much sense because it doesn't do anything other than return a true or false value in and of itself (which is why you're being warned that it's useless).

    Guessing from the context you're trying to assign something to $cust so you want the assignment operator = instead: $cust = 'SMC';.

    Update: And a bit more of a better long term solution would be to look into one of the standard argument parsing modules like Getopt::Long and use that instead of trying to cobble together your own.

    Another thing: I notice you give your option in your sample command line as -fet all lower case but you're comparing against -FET. String comparisons are case sensitive so that's not going to match (and even Getopt::Long wouldn't help you here). Pick a case and stick with it, or use lc (or uc) to canonicalize everything to one or the other before you attempt to compare them.

    The cake is a lie.
    The cake is a lie.
    The cake is a lie.

Re: Useless use of string eq
by naChoZ (Curate) on Dec 06, 2007 at 15:04 UTC

    I could be wrong, but this smells like a good opportunity to learn about Getopt::Long. I tend to use it with the hashref method like this.

    use Getopt::Long; my $opts = {}; # # maybe set some overridable defaults... # $opts->{target} = 'foo'; $opts->{cust} = 'SMC'; GetOptions( $opts, 'target=s', 'cust=s', 'cotime=s', );

    Now, if you type your_script.pl --target bar --cust FET --cotime baz then your $opts hashref will be populated accordingly. $opts->{target} will be 'bar', $opts->{cust} will be FET, $opts->{cotime} will be 'baz'. Setting defaults as I've demonstrated allows you to skip some of the command line args.

    --
    naChoZ

    Therapy is expensive. Popping bubble wrap is cheap. You choose.

Re: Useless use of string eq
by shmem (Chancellor) on Dec 06, 2007 at 15:08 UTC
    and depending what has been written there, alter a variable:
    ... if ($ARGV[1] eq '-SMC') {$cust eq "SMC";} ...

    You don't alter, you are comparing, twice. It's the second comparison ($cust eq "SMC") which leads to the warning. You mean:

    if ($ARGV[1] eq '-SMC') {$cust = "SMC";}

    But I guess for what you want, this is enough:

    #!/usr/local/bin/perl -w use strict; my($target, $cust, $cotime) = @ARGV; $cust =~ s/^-//; # strip leading dash

    --shmem

    _($_=" "x(1<<5)."?\n".q·/)Oo.  G°\        /
                                  /\_¯/(q    /
    ----------------------------  \__(m.====·.(_("always off the crowd"))."·
    ");sub _{s./.($e="'Itrs `mnsgdq Gdbj O`qkdq")=~y/"-y/#-z/;$e.e && print}
Re: Useless use of string eq
by jrsimmon (Hermit) on Dec 06, 2007 at 16:03 UTC
    To summarize some of the answers above:

    1. Why is this a useless use?
    Because eq is used to compare things. You are trying to use it to assign a value. You muse use = for that.

    2. What is a void context?
    {$cust eq "SMC";} is a void context, because you are performing a comparison (see 1.) but not doing anything with the result. There is not context for the compare, hence it is a void (empty) context.

    3. What can I do to do this better?
    The first reply Re: Useless use of string eq to your post by Fletch (++) explains best how to rewrite your code.

    Perhaps you should ask him about the whole children bearing thing...
Re: Useless use of string eq
by toolic (Bishop) on Dec 06, 2007 at 14:47 UTC
    You can also use diagnostics; to get more verbose help. In this case, I don't think it would have led you to the error that Fletch pointed out, but, I have found it to be useful in other instances.
Re: Useless use of string eq
by johngg (Canon) on Dec 06, 2007 at 17:08 UTC
    Another alternative would be to use a lookup table. It doesn't gain you much except, perhaps, readability in this particular instance where you are just losing the leading hyphen. However, it would be more useful in tranforming text further, e.g. 'UK' => 'United Kingdom'.

    use strict; use warnings; my ( $target, $cust, $cotime ) = @ARGV; my %lookup = ( q{-SMC} => q{SMC}, q{-FET} => q{FET}, q{-China} => q{China}, q{-SBM} => q{SBM}, ); if ( exists $lookup{ $cust } ) { $cust = $lookup{ $cust }; print qq{Customer set to $cust\n}; } else { warn qq{Customer $cust not recognized\n}; }

    I hope this is of use.

    Cheers,

    JohnGG

Re: Useless use of string eq
by sh1tn (Priest) on Dec 06, 2007 at 14:48 UTC
    In addition - you can achieve this assignment in one step:
    $cust = (split(/-/, $ARGV[1]))[1];


      That may admit bogus customers that don't exist, or that the program cannot deal with. It may be wiser to spell out exactly what is legal.

      (my $cust = $ARGV[1]) =~ s/^-(SMC|SBM|FET|China)$/$1/ or die "garbage in second arg: <$ARGV[1]>\n";

      • another intruder with the mooring in the heart of the Perl

Re: Useless use of string eq
by Flubb (Acolyte) on Dec 06, 2007 at 16:38 UTC
    Thanks everyone. I had somewhere concluded that = was for numbers only, which made me look elsewhere for eq.
    Re: Uppercase/Lowercase - I had stripped out the uc($var) bits but I forgot to tell you :( At somepoint there will be @ARGV checking, but I'm working my way slowly up!
    -
    Flubb
      I had somewhere concluded that = was for numbers only

      Mixing up with comparison operators. It is == that is for numbers, rather than eq for strings.
Re: Useless use of string eq
by NetWallah (Canon) on Dec 07, 2007 at 15:17 UTC
    If you installed the new perl 5.10, you could do something like:
    use feature qw(say switch); given($ARGV[1]) { when ('-SMC') { $cust= 'SMC'; } when ('-FET') { $cust= 'FET''; } # .... add other conditions ... # You can even use Regular expressions (Smart match) here, if nec +essary like::: when (/china/i) {$cust='China';} default { say 'Invalid customer'; } }

         "As you get older three things happen. The first is your memory goes, and I can't remember the other two... " - Sir Norman Wisdom

Re: Useless use of string eq
by mpeg4codec (Pilgrim) on Dec 07, 2007 at 23:29 UTC
    Others have already commented on why it's wrong, but I have some advice that should help make warnings and errors clearer: don't bunch up the code like that. Try writing it like this:
    #!/usr/local/bin/perl -w use strict; my($target, $cust, $cotime) = @ARGV; if ($ARGV[1] eq '-SMC') { $cust = "SMC"; } elsif ($ARGV[1] eq '-FET') { $cust = 'FET'; } elsif ($ARGV[1] eq '-China') { $cust = 'China'; } elsif ($ARGV[1] eq '-SBM') { $cust = 'SBM'; }
    In this case, the warnings can only be about a single statement, since only one statement ever appears on a given line. It's also a bit more appealing to look at (in my opinion), which is a bonus.