Beefy Boxes and Bandwidth Generously Provided by pair Networks
"be consistent"
 
PerlMonks  

'our' is not 'my'

by Ovid (Cardinal)
on Aug 16, 2001 at 21:05 UTC ( [id://105446]=perlmeditation: print w/replies, xml ) Need Help??

Update: At the request of a couple of people, some as replies to this node and one as a private message, I have added a link to this node from the Tutorials section. I have linked it rather than repost it to tutorials as there is no reason for me to get the rep twice. I might add that I would not have done this were it not for the high rep this node has received (thus suggesting to me that monks find this information useful).

Many people misunderstand how our is used and I've often seen code where it's used as a synonym for my. This is not the case and I hope this clears up some of the differences. I'm posting this because I've run across this a few times lately and I thought I should just 'get it out there' for others.

There are basically two ways of declaring variables in Perl: global and lexical. A global variable has a package name prepending to it:

$main::foo; $CGI::POST_MAX; @foo::bar;

All packages can access the variable $foo in the main symbol table (%main:: or the shorthand %::) by using $main::foo. Global variables are generally a bad idea, but do crop up in a lot of code.

A lexically scoped variable is declared with my:

my $foo; my $POST_MAX; my @bar;

Though they look similar to the package variables above, they are not the same and cannot be accessed outside of the scope in which they were declared.

If you use strict and you try to access a variable that's not previously declared, you'll get an error similar to the following:

Global symbol "$foo" requires explicit package name at C:\test.pl +line 2.

Basically, Perl expects that you are trying to use a package variable, but left off the package name. The problem with using package names ($main::foo) is that strict ignores these variables and if you type $main::field in one place and $main::feild in another place, strict won't warn you of the typo.

our tries to help out by letting you use package variables without adding the package name. The following two variables are the same:

package foo; use strict; our $bar; # These are the same $foo::bar; # These are the same

That eliminates the $main::f(ie|ei)ld problem by allowing you to do this:

our $field;

From there, you just drop package names and the script will run and later Perl will kill the script if you try use $feild. Unfortunately, there are a lot of problems with this.

The main problem is that you are now using global variables which is generally a Bad Thing. Any code, anywhere, can change your global. Large systems with lots of globals typically suffer this problems and quickly become unmaintainable.

This also leads to very subtle coding errors. Try the following code:

use strict; for ( 1 .. 3 ) { &doit } sub doit { our $foo; print ++$foo . "\n"; }

That will print 1, 2, and 3 on successive lines. Change the our to a my and it prints 1, 1, and 1. Because the my variable goes out of scope at the end of the sub and the our variable doesn't (since it's global), you get wildly different results.

There is one use I have found for our variables. if I am forced to maintain a large code base with lots of global variables, I usually expect to see lots of code problems, including misspellings of those globals that are overlooked due to the hacked nature of those code. For example, one site I worked on had some object-oriented code that stuffs a lot of data into package main (you can keep reading after you stop laughing). I've seen code like this:

$main::sql = $order->lineItemSQL; $main::dbh->prepare( $main::sql );

I know, it doesn't make a lot of sense (why doesn't it just return the line items instead of the SQL?), but I needed to clean up stuff like that. So, in my code, I put the following:

our ( $sql, $dbh ); #later $sql = $order->lineItemSQL; $dbh->prepare( $sql );

I didn't convert them to my variables because these variables were being declared in another package.

This doesn't seem like much benefit aside from eliminating a few bytes (and it certainly wasn't the best solution, but we've all had time constraints...). However, there is a huge benefit. Later in the code, when we encounter $main::slq, it becomes $slq and the program dies a much needed death.

As a side note: the primary difference (that I can see) between our and use vars appears to be that our lexically scopes the use of the variable name (not the variable) and the other does not. The following code snippets should clarify that:

use strict; { use vars qw/ $foo /; $foo = "Ovid"; } print $foo;

That code will work fine. However, change the use vars qw/ $foo /; to our $foo and Perl dies, telling you that $foo requires an explicit package name. However, change the print statement to include the package name and all is well:

use strict; { our $foo; $foo = "Ovid"; } print $main::foo;

This behavior may not seem immediately useful, but you can then use an our declaration at the top of a subroutine, strip off the package names in the sub, and not worry about this conflicting with my variables in the rest of the code.

use strict; my $foo = 'bar'; &baz; sub baz { our $foo = 7; print $foo; } print $foo;

Change that code to use "use vars" and you'll see it print 7 twice, stepping on your my variable.

Interesting to note that the only uses I've found for our have been hacking bad code...

Cheers,
Ovid

Vote for paco!

Join the Perlmonks Setiathome Group or just click on the the link and check out our stats.

Replies are listed 'Best First'.
Re: 'our' is not 'my'
by dragonchild (Archbishop) on Aug 16, 2001 at 23:35 UTC

    Good points, Ovid. ++! Personally, the only time I use our is in the following:

    use 5.6.0; use strict; use warnings; package Foo; use Exporter; our @ISA = qw(Exporter); our @EXPORT_OK = qw(bar baz); # Code down here, including bar() and baz()
    That way, I get to have the warmfuzzy feeling that I'm not using ickypoo globals, but, instead, using package-scoped globals. @ISA needing to be a global is why I even bother with our.

    ------
    /me wants to be the brightest bulb in the chandelier!

    Vote paco for President!

Re: 'our' is not 'my'
by damian1301 (Curate) on Aug 17, 2001 at 03:21 UTC
    I often see this error when people use the GetOpt modules. Good job Ovid, ++ (maybe could be a tutorial?).

    $_.=($=+(6<<1));print(chr(my$a=$_));$^H=$_+$_;$_=$^H; print chr($_-39); # Easy but its ok.
      I second the suggestion, I think it'd be perfect for the tutorial section! Ovid++!
Re: 'our' is not 'my'
by ikegami (Patriarch) on Oct 26, 2007 at 12:02 UTC

    There is a catch with our that doesn't exist with use vars:

    package AA; $AA::var = __PACKAGE__; our $var; print "$var\n"; package BB; $BB::var = __PACKAGE__; print "$var\n"; # Prints 'AA'.

    Using curlies when using multiple packages in one file avoids the problem.

    { package AA; $AA::var = __PACKAGE__; our $var; print "$var\n"; } { package BB; $BB::var = __PACKAGE__; print "$var\n"; # Compile error! }

    Keeping that exception in mind, our is like no strict 'vars'; on a per-var basis.

      In your first example, how is it that 'our $var;' in package AA makes $var available to both package BB and package main? Why does package BB fall back to AA's result without any kind of warning?

        I prefer to think of our as the equivalent of no strict 'vars' for a single variable, but in reality, our creates a lexically-scoped variable aliased to a package variable.

        In effect,
        our $var;
        is the same as
        use Data::Alias;
        alias my $var = $__PACKAGE__::var;
        (Syntax issues aside.)

        Unlike blocks and files, packages aren't lexical scopes. Switching package neither destroys the our variable (because the our variable is lexically scoped) nor change to which package variable the our variable is aliased (because package doesn't know anything about the our variable).

Re: 'our' is not 'my'
by Tabari (Monk) on Oct 26, 2007 at 11:55 UTC
    I was cleaning up some old code which did not use strict.
    As it used a lot of global vars, I was forced to use our, the way you explained. I didn't know the exact meaning before
    Tabari
Re: 'our' is not 'my'
by Anonymous Monk on Nov 20, 2008 at 19:47 UTC
    Is slq a typo?
    This line:
    However, there is a huge benefit. Later in the code, when we encounter $main::slq, it becomes $slq and the program dies a much needed death.

    Did you mean sql ?

    -J_Tom_Moon_79

      As I understand it, it's a deliberate typo to show that when using our, the typo called "slq" will get caught (instead of being treated like some new variable as happens when variables are global).

      So, maybe I'm misunderstanding (I don't write speak or read Perl yet, lawlz), but I thought "slq" was the whole point.

Log In?
Username:
Password:

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

How do I use this?Last hourOther CB clients
Other Users?
Others romping around the Monastery: (5)
As of 2024-11-01 20:32 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?
    chatterbot is...






    Results (6 votes). Check out past polls.