Beefy Boxes and Bandwidth Generously Provided by pair Networks
P is for Practical
 
PerlMonks  

Re: Unclear about 'our'

by haukex (Archbishop)
on Dec 27, 2022 at 17:02 UTC ( [id://11149137]=note: print w/replies, xml ) Need Help??


in reply to Unclear about 'our'

$foo::bar is a "package variable", sometimes referred to as a "global", although IMHO I prefer at least "package global", because the variable does belong to the package - see perlmod. our makes it so that the name $bar refers to $foo::bar in the lexical scope it is used. Outside of package foo;, you need to either refer to it by its full name $foo::bar, or you need to make a local alias to it, as for example is possible with Exporter; there are more ways to do it but these are the two I prefer depending on the situation. Here's an example for the latter:

foo.pm

package foo; use warnings; use strict; use Exporter 'import'; our @EXPORT_OK = qw/$bar/; our $bar = 42; 1;

script.pl

use warnings; use strict; use feature 'say'; use foo qw/$bar/; say $bar;

Replies are listed 'Best First'.
Re^2: Unclear about 'our'
by ibm1620 (Hermit) on Dec 27, 2022 at 17:26 UTC
    In your rewrite, could you have written my $bar = 42; instead?

    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.

      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!
        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.

      'our' gets you a "package global", accessible outside the package via <sigil>PACKAGE_NAME::var_name, or a variable that can be "imported" into your program's namespace.

      Hopefully, this code will clarify:
      FOO.pm

      package FOO; use warnings; use strict; use Exporter 'import'; our @EXPORT_OK = qw/$bar $baz Baz_Get_Set/; our $bar = 42; # Package global, visible as $FOO:bar my $baz = 66; # Not visible outside FOO - needs accessor sub sub Baz_Get_Set{ defined $_[0] and $baz=$_[0]; return $baz; } 1;
      pm11149136.pl
      use warnings; use strict; use feature 'say'; use lib "."; use FOO qw/$bar $baz Baz_Get_Set/; say "\$bar (an imported 'package' variable)=",$bar; say "\$bar (accessed explicitly via package name \$FOO::bar)=",$FOO::b +ar; $bar="Set via caller"; say "\$bar (accessed explicitly via package name \$FOO::bar after sett +ing via imported var)=",$FOO::bar; say "\$baz (direct attempt to access package 'my` variable)=",$baz; # +This returns UNDEF say "BAZ via getter/setter=",Baz_Get_Set(); # Nothing passed - this is + a GET say "BAZ get after setting to 55=", Baz_Get_Set(55);
      OUTPUT:
      bash-5.1$ perl pm11149136.pl $bar (an imported 'package' variable)=42 $bar (accessed explicitly via package name $FOO::bar)=42 $bar (accessed explicitly via package name $FOO::bar after setting via + imported var)=Set via caller Use of uninitialized value $baz in say at pm11149136.pl line 11. $baz (direct attempt to access package 'my` variable)= BAZ via getter/setter=66 BAZ get after setting to 55=55
      </c>

                      "These opinions are my own, though for a small fee they be yours too."

      The reason our appears to have little advantage over my is that you are misusing my.

      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.....

      Although this 'works', it is considered poor practice. It defeats the advantage of using my with use strict. Lexical (my) variables should be declared in the smallest possible scope. Accidental usage elsewhere will be detected at compile time. It is often useful to declare the same name in different scopes. (They actually refer to different variables). Both structured design and the newer object-oriented design discourage using subroutines that share a common pool of variables. Subroutines that do are much harder to test and debug than those that do not.

      Bill

        Both structured design and the newer object-oriented design discourage using subroutines that share a common pool of variables

        Structured code does not preclude shared variables.

        And the basis of OOP is the association of attributes (variables) with methods (subroutines). It's literally built around a common pool of variables.

        I think it's fair to say that, in object-oriented design, the fields/attributes/properties/member variables of a class are a common pool of variables shared by subroutines/methods. In fact, I've come to think of these as "globals with discipline", which is generally my thinking when I declare the variables I mentioned.

        However, as HaukeX suggested, it might be time to learn to write OO Perl. :-)

        > discourage using subroutines that share a common pool of variables

        I have to disagree in this generality, closures are a common technique.

        Cheers Rolf
        (addicted to the 𐍀𐌴𐍂𐌻 Programming Language :)
        Wikisyntax for the Monastery

      No, because Exporter would not be able to see it.

Log In?
Username:
Password:

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

How do I use this?Last hourOther CB clients
Other Users?
Others examining the Monastery: (4)
As of 2024-03-29 15:22 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found