in reply to Re^2: Unclear about 'our'
in thread Unclear about 'our'

In your rewrite, could you have written my $bar = 42; instead?

No, because lexical variables declared with my are limited in visibility to their lexical scope, in this case that's the file foo.pm; they don't show up in the package symbol table either. "Package globals" are "global" in the sense that you can reach across package boundaries to access other package's package variables - in the example here, you're reaching from package main into package foo. IMHO package globals are more and more rare and should nowadays only be used in places where they make sense.

Note that package variables can always be accessed by their fully qualified name, e.g. $foo::bar, while our creates a shorter alias to those package variables, and the visibility of that alias is the current lexical scope.

package foo; sub x { our $bar; # $foo::bar $bar++; my $quz; # a lexical $quz, not accessible outside this sub! } sub z { our $bar; # the *same* $foo::bar $bar++; my $quz; # a *different* lexical $quz } # no $bar here! but: sub w { $foo::bar++; # still the same $foo::bar }
In the modules and programs I've written, I typically declare a bunch of 'my' variables up top, outside of any blocks, which subsequent subroutines can freely access, so I'm still baffled by what 'our' buys me.

For example, if one of those my variables in your module was a default for something in one of the functions, then a user of your module could reach into your package and change that default, lexicals wouldn't allow this. (For debugging it's possible to inspect lexicals elsewhere, but this is not for production use.) I've whipped up a quick example of what I mean below.

One example might be that in Data::Dumper, one way to change its configuration options is via such package variables, as in $Data::Dumper::Useqq=1. However, it should be noted that this change is then global, so if you were to do it in a module, a user of your module might be surprised when their Data::Dumper changes behavior - the OO interface of the module is probably better in that case. Another thing is that only package variables, not lexicals, can be used in local to temporarily change their value in the current dynamic scope (the current call stack).

package bar; our $DEFAULT_QUZ = "World"; sub hello { my $what = shift || $DEFAULT_QUZ; print "Hello, $what!\n"; } package main; bar::hello(); # Hello, World! bar::hello("Alice"); # Hello, Alice! $bar::DEFAULT_QUZ = "Bob"; bar::hello(); # Hello, Bob!

Replies are listed 'Best First'.
Re^4: Unclear about 'our'
by ibm1620 (Hermit) on Dec 27, 2022 at 22:44 UTC
    I believe I've got it.

    In your package foo above, my inclination would be to declare 'my $bar;' at the top, before the first sub, and simply refer to it as '$bar', if there were no need for users in other packages to access it.

    In retrospect, I think using getters and setters is probably better than exposing variables.

    Thanks for your efforts to clear this up for me.

      In retrospect, I think using getters and setters is probably better than exposing variables.

      That's one way to do it, but I would actually recommend against that and suggest two alternatives instead. The reason is that if you simply encapsulate a global in getters/setters, then it's still a global, meaning you have the issue that one piece of code using your module might affect a different piece of code using the same module without meaning to, and also, if you don't use a package variable (our), that means that you're taking away the ability of users to use local to try and mitigate that effect.

      So instead, my suggestions would be to just use an our variable, either that or make the module OO and make this variable a property of the object. That means that different pieces of code can change their settings on their objects without affecting each other at all.

        I agree with your suggestion to make the module OO -- which means it's time to bite the bullet and learn how to write OO Perl. :-) I know there are various CPAN modules that support it; do you have a recommendation?