moderated >> Using a my expression with an if clause

by matt » Sat, 09 Jun 2007 05:32:27 GMT

A co-worker asked me about some odd behavior in a perl script. It
looked like a my variable in a loop was not getting reset to undef
during iterations. The my variable was declared with an if clause
(which is what causes the issue).

Here is a small script that duplicates the effect. The output of the
script follows.

############### SCRIPT START ############
#!/usr/bin/perl
use strict;

foreach my $i (0..10) {

print "start a=$i\n";

my $var = 'TWO' if $i == 2;
print "A: var = $var\n";

$var = 'FIVE' if $i == 5;
print "B: var = $var\n";

$var = 'EIGHT' if $i == 8;
print "C: var = $var\n";
}
############## SCRIPT END ################

Output of the script:
start a=0
A: var =
B: var =
C: var =
start a=1
A: var =
B: var =
C: var =
start a=2
A: var = TWO
B: var = TWO
C: var = TWO
start a=3
A: var =
B: var =
C: var =
start a=4
A: var =
B: var =
C: var =
start a=5
A: var =
B: var = FIVE
C: var = FIVE
start a=6
A: var = FIVE
B: var = FIVE
C: var = FIVE
start a=7
A: var = FIVE
B: var = FIVE
C: var = FIVE
start a=8
A: var = FIVE
B: var = FIVE
C: var = EIGHT
start a=9
A: var = EIGHT
B: var = EIGHT
C: var = EIGHT
start a=10
A: var = EIGHT
B: var = EIGHT
C: var = EIGHT

At the end of iteration a=2, the value of $var was set back to undef
(which is what I expected).
However, at the end of iteration a=5, $var seems to retain its value
during the next iteration of the loop (which I did not expect).

We fixed the issue by separating out the my $var declaration from the
if clause:
my $var;
$var = 'TWO' if $i == 2;

However, I don't understand why it behaved the way it did.

I tried searching the web, but the only thing close I found was
"variable suicide" which doesn't seem to be the issue.

My perl version (fromCentOS release 4.4) :
$ perl -v
This is perl, v5.8.5 built for i386-linux-thread-multi

moderated >> Using a my expression with an if clause

by Gunnar Hjalmarsson » Sat, 09 Jun 2007 08:10:27 GMT



When used like:

my $var = 'TWO' if $i == 2;

the "if $i == 2" part is called a "statement modifier". Quoted from the
"Statement Modifiers" section in "perldoc perlsyn":

"NOTE: The behaviour of a my statement modified with a statement
modifier conditional or loop construct (e.g. my $x if ...) is undefined.
The value of the my variable may be undef, any previously assigned
value, or possibly anything else. Don't rely on it. Future versions of
perl might do something different from the version of perl you try it
out on. Here be dragons."


You should have tried the Perl documentation...

--
Gunnar Hjalmarsson
Email: http://www.gunnar.cc/cgi-bin/contact.pl

moderated >> Using a my expression with an if clause

by Jim Gibson » Sat, 09 Jun 2007 08:48:37 GMT

In article < XXXX@XXXXX.COM >,



[rest of test program and output snipped]


The effect of 'my' in a conditional statement is undefined. See the
section "Statement Modifiers" in 'perldoc perlsyn', especially the
'NOTE' at the end. You have already arrived at the solution, which is
"don't do that".

moderated >> Using a my expression with an if clause

by Brian McCauley » Sat, 09 Jun 2007 15:28:10 GMT


Why after so long is it still undefined?

Why is it not simply an error?

moderated >> Using a my expression with an if clause

by Gaal Yahas » Sat, 09 Jun 2007 20:52:22 GMT


Possibly because "my $x if 0" is used In the Wild as a trick to get
static variables.

Sure, there exists a clearly better way to do it (surround the function with a
new scope and declare my $x there), but making this an error will
break old code.

ObPerl6: "state $x"

--
Gaal Yahas < XXXX@XXXXX.COM >
http://gaal.livejournal.com/

moderated >> Using a my expression with an if clause

by Uri Guttman » Sun, 10 Jun 2007 01:53:03 GMT

>>>>> "BM" == Brian McCauley < XXXX@XXXXX.COM > writes:


>> "NOTE: The behaviour of a my statement modified with a statement
>> modifier conditional or loop construct (e.g. my $x if ...) is
>> undefined.

BM> Why after so long is it still undefined?

BM> Why is it not simply an error?

it was discovered early on that this is a bastard technique to get a
static lexical inside a block/sub. so it is used a bit even if it was
never defined to work this way. too much code uses it to allow it to be
just made into an error now. what is more annoying is that the proper
way to do this (an outer block with the lexical in it) is easy enough
and wasn't used by those who took this error route.

uri

--
Uri Guttman ------ XXXX@XXXXX.COM -------- http://www.stemsystems.com
--Perl Consulting, Stem Development, Systems Architecture, Design and Coding-
Search or Offer Perl Jobs ---------------------------- http://jobs.perl.org

moderated >> Using a my expression with an if clause

by Ilya Zakharevich » Wed, 13 Jun 2007 00:27:26 GMT

[A complimentary Cc of this posting was sent to
Jim Gibson
< XXXX@XXXXX.COM >], who wrote in article <080620071748378798% XXXX@XXXXX.COM >:

This is too strong a summary. 'my' is fine in the "condition" part of
the statement (as far as you agree to not use this variable in the
same statement; sigh...); not, if it GOVERNED by a conditional.

In a pedantic mode,
Ilya

Similar Threads

1. MySQL support for NULL in WHERE clause - Perl DBI

2. problem in LIMIT clause

hi,
  i am trying to use LIMIT clause to retrieve a range of records from a
CSV but its neither working, nor giving any error. instead, it displays
all records...

the test code is below,

waiting for reply
Regards,
Anurag.


CODE ::


use DBI;

use File::Basename;
($csvfile,$csv_path) = fileparse($ARGV[0], '/');


my $dbh = DBI->connect("DBI:CSV:f_dir=$csv_path;csv_eol=\n;");


$dbh->{'csv_tables'}->{$csvfile} = {
        'col_names' => [ "conn", "pid", "time", "size", "client",
"contenttype", "status", "categ", "reason", "domain", "url" ]
};


# test LIMIT clause
print "Preparing test LIMIT clause...\n";
$sth = $dbh->prepare("SELECT * from $csvfile limit 10");


$sth->execute();
my $mycount = 0;
while ($count = $sth->fetchrow_hashref) {
        $mycount++;
}
print("LIMIT 10: found $mycount records in $csvfile\n");

$sth->finish();
exit;


OUTPUT::
[root@anurag bin]# ./test_ws_tablegen CSVToday
Preparing test LIMIT clause...
LIMIT 10: found 96832 records in CSVToday
[root@anurag bin]#

3. Perl: grep in if clause - Perl

4. Many SQL clauses executing

Hello there!

I tried to execute many SQL-clauses ";" separated by DBI::do() method 
but got an error message about SQL syntax mistake. If I execute the same 
SQL from MySQL shell or some MySQL GUI all works fine. Is DBI::do() 
method able to perform many SQL clauses at all? If no what method or 
function should I use to perform this?


Thanks in advance.

5. if -s clause - Perl

6. conditional use clause

Hi folks.

I'm moving on with my Trainset project and I've got to the point where I want 
to develop Trainset::Tk to create a user interface for someone setting in a 
signalbox.

To do this, I've created Trainset/Tk.pm as below, and included a 

use Trainset::Tk;

in my Trainet.pm.  The problem I have is that on some of my development boxes 
I don't have Tk installed.  This then prevents me from running the program 
even though I'm not actually wanting to *use* the Tk modules (most of my work 
is developing the logic engine in text mode).

Is there a way to only 'use Trainset::Tk' conditionally, or even better, have 
it auto-detect the availability and simply ignore it if it's not there.
-- 
Gary Stainburn
 
This email does not contain private or confidential material as it
may be snooped on by interested government parties for unknown
and undisclosed purposes - Regulation of Investigatory Powers Act, 2000     

7. if-clause again - Perl

8. Where Clause Help.

I believe this is a very simple question or at least I'm hoping ...

I am trying to select items from a table where the miles field is not
null or blank and the below statement does not work.  Does anyone have
any suggestions?

Thanks!

 

            @resultkeys = ("Date","People","Miles","Savings");

            $sql = "SELECT c.objectid,c.dateadded as
\"Date\",c.totalpeople as \"People\", ";

            $sql .= "c.miles as Miles, c.totalsaved as \"Savings\" ";

            $sql .= "FROM OWNER.CONFERENCE c";

            $sql .= " WHERE c.miles <> "";

            $sql .= " ORDER BY c.datestart";