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

I am trying to create an if loop as well as use strict. why does this block keep telling me to define $zipexe?
use strict; #determine zip location and then addid to the environment if(-f 'c:\program files (x86)\winzip\wzzip.exe') { print 'Setting zip exe location to c:\program files (x86)\winzip\w +zzip.exe'."\n"; my $zipexe="c:\\program files (x86)\\winzip\\wzzip.exe"; print "zip_exe = <$zipexe>\n"; } if(-f 'c:\program files\winzip\wzzip.exe') { print 'Setting zip exe location to c:\program files\winzip\wzzip.e +xe'."\n"; my $zipexe ='"c:\program files\winzip\wzzip.exe"'; print "zip_exe = <$zipexe>\n"; }else{ my $zipexe=''; die "Could find wzzip.exe"; } print "zip_exe = <$zipexe>\n";

Replies are listed 'Best First'.
Re: Stupid If Question
by ikegami (Patriarch) on Aug 18, 2009 at 21:03 UTC
    When you declare a variable, it's only visible within the block in which it's declared and block contained within. To which var do you think the last $zipexe refers?
      My thought was since it was defined in each of the if parts that it would be difined after the if statements... Maybe i don't understand what you mean?

        Three variables were defined, one in each block. (Blocks which aren't even mutually exclusive, I might add.) A fourth variable doesn't magically become defined elsewhere as a result. I believe you want

        my $var; if (...) { $var = ...; } elsif (...) { $var = ...; } else { die; }
        Since the variable is used in three different places you can declare it right at the top, and hence the scoping of it would be such that it is available to the entire code. When you declare a variable inside blocks (i.e. {} ) the scope of that variable determines its visibility only inside that block and within it.

        use strict; my $zipexe;
        thumbs-up for using "strict"...keep up the good work :)

        Excellence is an Endeavor of Persistence. Chance Favors a Prepared Mind.

        Three variables were defined, one in each block. (Blocks which aren't even mutually exclusive, I might add.) A fourth variable doesn't magically become defined elsewhere as a result. I believe you want

        my $var; if (...) { $var = ...; } elsif (...) { $var = ...; } else { die; }
Re: Stupid If Question
by Bloodnok (Vicar) on Aug 19, 2009 at 10:52 UTC
    In addition to all the earlier answers to your question, I submit that there's no such thing as a stupid question [about perl] where it's obvious that, despite best efforts, something doesn't quite gell - we all have to learn sometime.

    Furthermore, I'd be prepared to guarantee that your experience on/in the Monastry will contribute to your remembering the lesson(s) learnt :-D

    Moreover, I'd be very surprised indeed if, thro' the question you asked, you didn't pave the way for others to gain understanding...

    Just my 2 penn'orth

    A user level that continues to overstate my experience :-))
Re: Stupid If Question
by GrandFather (Saint) on Aug 19, 2009 at 21:58 UTC

    The important idea to understand here is 'scope'. Scope describes the chunk of code where an identifier is recognized as being tied to a specific something (variable name, subroutine name, ...). For lexical variables (the ones declared using my) the scope is from the declaration to the end of the current block. {} is used to enclose a block and they may be nested (blocks in blocks).

    In your sample you had three blocks, each with a (different) variable called $zipexe declared in it. Since each $zipexe goes out of scope (can't be seen any more) at the end of the block it is declared in, none are visible in the outer block containing the print statement. To fix the problem you need to have just one declaration for $zipexe before the first if so that the same variable is used in each place.

    Note that this is a feature and contributes to why strict can pick up coding errors. If you make a habit of declaring variables in the smallest sensible scope strict can often let you know when you are trying to use a variable inappropriately (as indeed was the case here).

    Note that as well as using strict you should also use warnings which will tell you about things that are going wrong at run time, such as the contents of variable being used before the content has been set (a very common problem btw).


    True laziness is hard work
Re: Stupid If Question
by Marshall (Canon) on Aug 19, 2009 at 03:32 UTC
    First, EVEN ON WINDOWS:
    #!/usr/bin/perl -w use strict;
    Windows does NOT care about the path to Perl, BUT it does care about the -w (use warnings). This standard header will work on both Unix and Windows.

    Second, This "back-slash" versus "forward-slash" stuff can be a mess! The ANSWER is that Perl has fixed this! Always use Unix "/" for all path names known to Perl. $root = "C:/xyzzy", NOT "C:\\xyzzy"! Perl will translate the "/" to back slash when needed, which relieves you of the problem of having to code "\\path" vs "/path". This "escape char" stuff is a HUGE source of errors and its not needed.

    Third, using characters that could have meaning within a print statement (like < or >) can potentially get you into trouble. This is the time for "\", or just using commas to separate tokens:

    print "zip_exe = "<",$zipexe,">\n"; #"<$zipexe>$x" might not parse "right" in the #general case although usage in above code appears ok..
    I've seen code before that uses the "." concatenation op instead of just a simple comma. In Perl this is just not necessary. Use "," when you can do so.

      Perl will translate the "/" to back slash when needed

      I doubt it since the OS happily accepts "/" as a path separator.

      While the following isn't proof, it would surprise most:

      C:\Documents and Settings\ikegami>dir "c:/bin" Volume in drive C is C Volume Serial Number is 28AB-0E8B Directory of c:\bin 2008/12/21 10:53 PM <DIR> . 2008/12/21 10:53 PM <DIR> .. . . .
        There are differences in MS OS, consider:

        Microsoft Windows XP [Version 5.1.2600] (C) Copyright 1985-2001 Microsoft Corp. C:\Projects>cd /temp The system cannot find the path specified. C:\Projects>cd \temp C:\TEMP>
        There can be weird things with "\". I am just saying for the most part, use "/" instead of "\\". I think we agree on that!
      Not even on windows :)
      #!/usr/bin/perl -- use strict; use warnings;
      Get with the times, -w is dead, long live warnings :D
        Wrong.

        -w shebang option is alive and well at least in Perl 5.10. And yes this is supported on Windows (not the path), but the -w option just like I said.

        Update: For folks that didn't read the previous:

        #!/usr/bin/perl -w use strict;
        should be almost like a mantra on Unix or on Windows!