Extremely peculiar behavior in a loop in a subroutine 
Author Message
 Extremely peculiar behavior in a loop in a subroutine

Please look at the subroutine below.  The problem is the if statement.
At first, where I now have "$level = 0" I had "next", but that exited
the entire subroutine with the message:

Exiting subroutine via next at final line 139, <STDIN> chunk 2 (#1)
Exiting subroutine via next at final line 139, <STDIN> chunk 2.

So then I changed it to what you see below.  Now in all my years of
programming it has always been my experience that setting a test
variable to a number guaranteed to fail will cause the conditional test
to fail, but in this case if the user enters something that doesn't
begin with a digit, $level is set to 0 and 0 is returned.

Why?

sub getNumber
{

  local($level);

 do {
    $level = <STDIN>;
    if ($level !~ /^\d/) {
      print "please enter a number\n";
      $level = 0;
    }
  } while ($level < 1 && $level > $maxNum);

  $level;

Quote:
}

--
Best regards,

       Charles Herold
         Pathfinder
          Production Assistant

             (212) 522-5190



Fri, 14 Jan 2000 03:00:00 GMT  
 Extremely peculiar behavior in a loop in a subroutine



Quote:
>Please look at the subroutine below.  The problem is the if statement.
>At first, where I now have "$level = 0" I had "next", but that exited
>the entire subroutine with the message:

>Exiting subroutine via next at final line 139, <STDIN> chunk 2 (#1)
>Exiting subroutine via next at final line 139, <STDIN> chunk 2.

that's because do { } while (...); isn't really a loop, so the loop
control operators are looking for some enclosing loop to do the next on.

Quote:
>So then I changed it to what you see below.  Now in all my years of
>programming it has always been my experience that setting a test
>variable to a number guaranteed to fail will cause the conditional test
>to fail, but in this case if the user enters something that doesn't
>begin with a digit, $level is set to 0 and 0 is returned.
>Why?

because your condition is suspect:

  while ($level < 1 && $level > $maxNum)

requires both $level to be < 1 and $level to be > $maxNum to succeed, and
assuming that $maxNum is a positive integer that will be a hard condition
to meet...

Quote:
>sub getNumber
>{

>  local($level);

> do {
>    $level = <STDIN>;
>    if ($level !~ /^\d/) {
>      print "please enter a number\n";
>      $level = 0;
>    }
>  } while ($level < 1 && $level > $maxNum);

>  $level;
>}

You may want to say something along the lines of this un-tested code:

sub getNumber {
  my $maxNum = shift;
  my $level = 0;

  until ($level >= 1 and $level <= $maxNum) {
    chomp ($level = <STDIN>);
    unless ($level =~ /^\s*\d+\s*$/) {
      print "please enter a number\n";
      $level = 0;
      next;
    }
  }

  $level + 0;                           # strip any spaces

Quote:
}

Hope this helps,

Mike

--

http://www.stok.co.uk/~mike/       |   PGP fingerprint FE 56 4D 7D 42 1A 4A 9C
http://www.tiac.net/users/stok/    |                   65 F3 3F 1D 27 22 B7 41



Fri, 14 Jan 2000 03:00:00 GMT  
 Extremely peculiar behavior in a loop in a subroutine

Quote:

> Please look at the subroutine below.  

I did.

Quote:
> The problem is the if statement.

I don't think so.

Quote:
> At first, where I now have "$level = 0" I had "next", but that exited
> the entire subroutine with the message:

> Exiting subroutine via next at final line 139, <STDIN> chunk 2 (#1)
> Exiting subroutine via next at final line 139, <STDIN> chunk 2.

I believe that perl is trying to tell you that "next" doesn't really
mean what you think it means in this context.  You might think that it
would mean that it should go back to the top of the do loop, but it
doesn't.

Quote:
> So then I changed it to what you see below.  Now in all my years of
> programming it has always been my experience that setting a test
> variable to a number guaranteed to fail will cause the conditional test
> to fail, but in this case if the user enters something that doesn't
> begin with a digit, $level is set to 0 and 0 is returned.

> Why?

Because you have an && where you want an ||.

Quote:
> sub getNumber
> {

>   local($level);

>  do {
>     $level = <STDIN>;
>     if ($level !~ /^\d/) {
>       print "please enter a number\n";
>       $level = 0;
>     }
>   } while ($level < 1 && $level > $maxNum);

                        ^^
                        ||
                      Right here, should be ||.

Quote:

>   $level;
> }

Also:
        1.  use "my" vice "local"
        2.  use "chomp $level" to get rid of that pesky return and look for
                $level !~ /^\d*$/
        3.  This is vulnerable to someone typing "3c" since it only
            checks the first value.
        4.  Personal programming technique:  use an explicit return value.

For what it's worth, I'd do:

sub getNumber {

   my ( $level );

   $level = <STDIN>;
   chomp $level;
   while ( $level !~ /^\d*$/ or
           $level < 1        or
           $level > $maxNum) {
      print "Please enter a number \n";
      $level = <STDIN>;
      chomp $level;    
   }
   return $level;

Quote:
}

But, aren't we doing a numerical check with the $level < 1  and isn't
        that bad?
No, I don't think so since the test gets short-circuited by the "or".

Aren't we being repetitive with the multiple <STDIN>'s and chomps?
Yes, but clarity beats conciseness any day in my book.

To get rid of the repetitive stuff, you can use a label and use
"redo".  In fact, you might want to take a look at redo function in perlfunc.

sub getNumber {

   my ( $level );

 LOOP: {
      $level = <STDIN>;
      chomp $level;
      if ($level !~ /^\d*$/) {
         print "please enter a number\n";
         redo LOOP;
      }
      redo LOOP if $level < 1;
      redo LOOP if $level > $maxNum;
   }
   return $level;

Quote:
}

--
Clark


Fri, 14 Jan 2000 03:00:00 GMT  
 Extremely peculiar behavior in a loop in a subroutine

Charles> Please look at the subroutine below.  The problem is the if statement.
Charles> At first, where I now have "$level = 0" I had "next", but that exited
Charles> the entire subroutine with the message:

Charles> Exiting subroutine via next at final line 139, <STDIN> chunk 2 (#1)
Charles> Exiting subroutine via next at final line 139, <STDIN> chunk 2.

"do ... while" loops are not real loops.  They're a bizarre
combination of a do {} and a backwards while.

As such, they cannot support last/next/redo without breaking older
code.

Charles>  do {
Charles>     $level = <STDIN>;
Charles>     if ($level !~ /^\d/) {
Charles>       print "please enter a number\n";
Charles>       $level = 0;
Charles>     }
Charles>   } while ($level < 1 && $level > $maxNum);

I'd write this as:

        {
                $level = <STDIN>;
                last if $level >= 1 and $level <= $maxNum;
                print "please enter a number again\n";
                redo;
        }

Yes.  A {*filter*} block.  Not a do-while block.

print "Just another Perl hacker," # but not what the media calls "hacker!" :-)
## legal fund: $20,495.69 collected, $182,159.85 spent; just 399 more days

--
Name: Randal L. Schwartz / Stonehenge Consulting Services (503)777-0095
Keywords: Perl training, UNIX[tm] consulting, video production, skiing, flying

Web: <A HREF=" http://www.*-*-*.com/ ;>My Home Page!</A>
Quote: "I'm telling you, if I could have five lines in my .sig, I would!" -- me



Fri, 14 Jan 2000 03:00:00 GMT  
 
 [ 4 post ] 

 Relevant Pages 

1. Peculiar Behavior with $val = $val2 =~ s///;

2. Peculiar behavior of system()

3. peculiar pattern matching behavior

4. Wierd loop/chdir behavior

5. behavior in a while loop

6. Weird behavior when using foreach loop and references

7. Strange behavior in do while loops in perl 5.00503

8. Q: Strange behavior writing text during FOREACH loop

9. Passing filehandles to subroutines and local() behavior.

10. weird behavior when passing hashes to subroutine

11. Strange behavior of multiply defined subroutines

12. Strange behavior in subroutine

 

 
Powered by phpBB® Forum Software