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

Sorry for the length and code sloppiness...


Here's some sample code:
use strict; use warnings; my $baz = 0; my $foo = shift || 1; chomp(my @bar = qw( etc etcetera )); die "Nice Try." if $foo < 1; while($baz < $foo){ $baz += 1; print "$bar(bracket)rand @bar(/bracket) ", "ad infinitum\n"; }
Now, my problem with the code as it is(will change later in post) comes when I try to put 0 as a command line option when excecuting the script.

As it is, if you type 0 at the command line, it will still execute, with only one result, as though it had 1 or no option typed at the command line.

I'm guessing it has to do with the nature of the +=, that it will do something even when other commands tell it not to.

I did find a workaround, almost by accident.

Change || to or. However, if you use the default by not typing in an option, it will give this error:

Use of uninitialized value in numeric lt (<) at footest.pl line 9. Nice try. at footest.pl line 9.

Now, I tried a workaround, by changing "shift or 1," to "shift or die." This sort of works, but what happens is that, 1. You have to type a command line option or it will die, and more interestingly, 2. if you type 0 at the command line, it will give the error message for the "shift or die" line, rather than the other die message.

I just checked it by changing the second die line to < 2 and got the error messages like this:

perl footest.pl 1
Nice try. at footest.pl line 9.

perl footest.pl 0
Died at footest.pl line 6.

perl footest.pl -1
Nice try. at footest.pl line 9.

So...I'm thinking that 0 has some sort of special property here, that's making it act that way. Perhaps, as a guess, having to do with it's characteristic as being one of the things that means false?

20050102 Edit by ysth: code and p tags

Replies are listed 'Best First'.
Re: fun(?) with +=
by davorg (Chancellor) on Jan 02, 2005 at 22:38 UTC

    Your problem is with the line

    my $foo = shift || 1;

    Consider what happens if you give this program a command line argument of 0.

    "shift" returns the value of the first command line argument - which is 0, therefore "shift || 1" will be 1.

    You need to think about the difference between the truth value of a variable and it's defined value. You want to check that your command line argument is defined - not that it is true.

    You probably want something like this:

    $foo = shift; $foo = 1 unless defined $foo;

    In Perl 5.10 you'll be able to use the "defined or" test to make this code easier.

    $foo = shift // 1;
    --
    <http://www.dave.org.uk>

    "The first rule of Perl club is you do not talk about Perl club."
    -- Chip Salzenberg

      I'd write that as:
      $foo = @ARGV ? 1 : shift;
      which, IMO, gives a clearer message that '1' the default if no arguments are given.
        Do you mean that you'd write it as:

        $foo = @ARGV ? shift : 1;

        (I think you may have the 1 and shift switched.)

Re: fun(?) with +=
by itub (Priest) on Jan 02, 2005 at 23:39 UTC
    Be careful with "trial and error programming" (also called "programming by accident"). It is always better to understand what you are doing. In this particular case, the problems are in operator precedence and in "what is truth?", both covered in detail in any Perl book or in perldoc.
      After studying up a bit on defined, finally figured out what to do. Here is the code

      #!/usr/bin/perl use strict; use warnings; my $baz = 0; my $foo = shift; $foo = 1 if !defined($foo); chomp(my @bar = qw( etc etcetera )); die if $foo < 1; while($baz < $foo){ $baz += 1; print "$bar[rand @bar] ", "ad infinitum\n"; }

      It returns a single result if nothing is entered at command line, and it returns error message if you select 0 or less at the command line. It works properly in every other respect as well.

      Thanks, Perlmonks!
        Update: This is redundant; davorg already said it above!

        Since what you wanted to do is a common need, future versions of perl are supposed to include a "defined-or" operator:

        $x //= 1; # same as $x = $x // 1;

        will be equivalent to

        $x = defined $x ? $x : 1; # same as $x = 1 unless defined $x

Re: fun(?) with +=
by ccn (Vicar) on Jan 02, 2005 at 22:36 UTC

    Please note that:

    $foo = shift || 1; # is the same as $foo = (shift || 1);
    and
    $foo = shift or 1; # is the same as ($foo = shift) or 1;

    see perldoc perlop about Operator Precedence

      $ perl -MO=Deparse,-p -e'$foo = shift || 1' ($foo = (shift(@ARGV) || 1)); -e syntax OK

      Makeshifts last the longest.