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!