Beefy Boxes and Bandwidth Generously Provided by pair Networks
Welcome to the Monastery
 
PerlMonks  

using strict and functions

by idunno (Beadle)
on Jan 17, 2002 at 21:42 UTC ( #139560=perlquestion: print w/ replies, xml ) Need Help??
idunno has asked for the wisdom of the Perl Monks concerning the following question:

I have some variables that I need to use in several functions. I also want to use strict;. What's the best way to use these variables where I need to without making them global?

Thanks.

Comment on using strict and functions
Download Code
Re: using strict and functions
by runrig (Abbot) on Jan 17, 2002 at 22:01 UTC
    You can localize them to the functions (the 'BEGIN' is so that any initializations to the variables get done no matter where you place these functions in the program):
    BEGIN { my ($var1, $var2) = ("this", "that"); sub sub1 { # use $var1, $var2 } sub sub2 { # use $var1, $var2 } }
    Update: It's hard to tell what you really want or need from your description, so its a good thing there are lots of good answers here..

      This turns sub1 and sub2 into closures (see 'What's a closure?'). While it is not always necessary to use BEGIN blocks, without them (i.e. normal blocks), declaration order becomes significant.

      Update: A trick I use occasionally is to declare a set of lexical variables in a BEGIN block along with access functions. Within the program, only the access functions are visible.

      BEGIN { my ($var1, $var2, $var3); my @array1; my %hash1; sub var1 { $var1 = $_[0] if @_; $var1 } sub var2 { $var2 = $_[0] if @_; $var2 } sub var3 { $var3 = $_[0] if @_; $var3 } # for arrays and hashes, call in scalar context and # dereference to manipulate contents sub array1 { wantarray ? @array1 : \@array1 } sub hash1 { wantarray ? %hash1 : \%hash1 } }

      Of course, rather than hand code access functions for every variable, I typically define a hash containing my variables as keys, and an AUTOLOAD to define access functions dynamically on first use.

      dmm

      If you GIVE a man a fish you feed him for a day
      But,
      TEACH him to fish and you feed him for a lifetime
Re: using strict and functions
by Desdinova (Friar) on Jan 17, 2002 at 22:04 UTC
    One way would be to add
    use vars qw($var1 @array2};
    That will give you the effect of a global var (actually a package var.) Without strict complaining too much. There is a great discussion of this here

    Another option would be to pass the functions a reference to the variable. See perlref for details on using references. In my opinion this is a better way because it makes your functions more usable in other programs.
    Also if they are small vars you can just pass them to the function in your call. If it is a huge list you will get better performance with the reference though.

    UPDATE: Removed the comma per the comment below btw- you are bieng no more 'picky' than perl itself <g>

      Sorry to nitpick but you can do either this:

          use vars qw($var1 @array2);

      or this:

          use vars ( '$var1', '@array2' );

      but using a comma within a qw() list includes the comma in whatever word(s) it touches.

      Other than that, ++!

      dmm

      If you GIVE a man a fish you feed him for a day
      But,
      TEACH him to fish and you feed him for a lifetime
Re: using strict and functions
by strat (Canon) on Jan 17, 2002 at 22:04 UTC
    There are some variables that can't be used with my, e.g. $" or the like. In this case, you have to use local.
    sub MyFunc { local $" = shift; my @list = @_; print "@list\n"; } # MyFunc
    But always try to use my before using local.

    Best regards,
    perl -e "print a|r,p|d=>b|p=>chr 3**2 .7=>t and t"

Re: using strict and functions
by talexb (Canon) on Jan 17, 2002 at 22:16 UTC
    In addition to the excellent technical answers you're getting, let me also add a style comment.

    Only declare variables when you need them. If you need a loop variable, don't declare it away at the beginning of the routine or (horrors!) at the top of the file. Just declare it where you're gonna need it, like this:

    for ( my $Index = 0; $Index < 5; $Index++ ) { ... # code here that uses $Index }
    If you're going to need two variables somewhere in the middle of a block of code, declare them there. In some languages you do have to declare all variables at the beginning (Pascal, and I think BASIC) .. but C and Perl give you more flexibility. So you could write
    { # Start black of code .. .. { # Start another block of code my ( $Index, $NodeNumber ); .. .. } .. .. }
    This just declares the two variables where you need them. As soon as the scope (the code between the braces) ends, the variables disappear. Very neat, very clean.

    --t. alex

    "Of course, you realize that this means war." -- Bugs Bunny.

      In some languages you do have to declare all variables at the beginning (Pascal, and I think BASIC) .. but C and Perl give you more flexibility.

      Hmm...I think you meant to say C++ here. C doesn't give you that kind of flexibility; however, C++ does.

      metadoktor

      "The doktor is in."

        Hmm...I think you meant to say C++ here. C doesn't give you that kind of flexibility; however, C++ does.
        #include <stdio.h> int main ( int iArgC, char * apsqArgV[] ) { printf ( "Hello, world! This is cygwqin speaking.\n" ); { char szMsg[] = "Not so!"; printf ( "Now inside scope, msg is %s.\n", szMsg ); } return ( 0 ); // Success is zero in Windows. }
        This is the kind of scope that I was talking about. The char array szMsg is declared at the start of the scope; this code compiles and runs correctly under CygWin (Win98).

        You may have been talking about the following:

        void FooBar ( void ) { int iBeer, iVodka; float fCredit = 20.0; .. /* Code here */ iBeer++; fCredit -= 2.50; .. /* More code */ char *apszVarious[]; /* ILLEGAL in C */ }
        I will grant that this kind of variable declaration is valid in Perl but not valid in C.

        --t. alex

        "Of course, you realize that this means war." -- Bugs Bunny.

      One point here ... Your use of the loop construct of for (;;) is very C-stylish and possibly not the best way to perform a simple forward iteration as your suggest. A more straight-forward way would be to make use of the range operator. eg.
      for (0..5) { # stuff goes here }

      If you require lexical scoping of the iteration variable, you can do so with the variable name and the my keyword.

      This syntax and the range operator are discussed in perlsyn and perlop respectively.

       

      perl -e 's&&rob@cowsnet.com.au&&&split/[@.]/&&s&.com.&_&&&print'

Re: using strict and functions
by mirod (Canon) on Jan 17, 2002 at 22:40 UTC

    You can also declare a global hash (or array, but a hash is more convenient) containing the variables and pass it around as a parameter to the functions:

    my $state= { var1 => "value1", var2 => "value2"}; sub f1 { my( $other_param, $state)= @_; $state->{var2}= "new_value2"; # ... } ...

    This way you group the variables together cleanly and you can pass them to the functions without clobbering your parameter lists.

    Of course if you want to get OO brownie-points you can also make $state an full-blown object, but that would be an other story node...

Re (tilly) 1: using strict and functions
by tilly (Archbishop) on Jan 18, 2002 at 22:49 UTC
    This looks to me to be an example of believing that a fundamental issue can be fixed by renaming what you are doing.

    It doesn't work like that.

    The effect that you are trying to achieve is that of a global. If you succeed in achieving that effect, you will have all of the fundamental design advantages and disadvantages that globals have. (They do have both.) The mechanism that you use to achieve the effect has no relevance beyond the fact that you are imposing overhead and obscuring what you are doing.

    This is why I recommend that people not just understand that something is bad, but also understand why it is bad. We tend to complain of "cargo cult" code where people borrow code by rote without understanding. But the flip side of the same coin is no better in the end, accepting that certain labels are bad without understanding why.

    Therefore, unless you want a specific subtly different effect than what globals give, I would be honest about it and just declare a global with vars. Oh, every alternative will have small advantages and disadvantages over this. For instance using a single global hash gives you only "one" global - but you impose overhead and lose typo checking.

    For more on the issues with globals, and how changing the label does (not) address them, see Pass by reference vs globals.

Log In?
Username:
Password:

What's my password?
Create A New User
Node Status?
node history
Node Type: perlquestion [id://139560]
Approved by root
help
Chatterbox?
and the web crawler heard nothing...

How do I use this? | Other CB clients
Other Users?
Others lurking in the Monastery: (8)
As of 2014-12-25 04:39 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    Is guessing a good strategy for surviving in the IT business?





    Results (159 votes), past polls