Question

I was looking at this question, and while I was playing around, I came across this:

#! /usr/bin/env perl
#
# use warnings;
use strict;
use feature qw(say);

{
    our $foo = "bar";
    say "Foo = $foo";
}

say "Foo = $foo";  # This is line #12

Yes, I do have use warnings; turned off...

When I run this, I get:

Variable "$foo" is not imported at ./test.pl line 12.
Global symbol "$foo" requires explicit package name at ./test.pl line 12.
Execution of ./test.pl aborted due to compilation errors.

Hmmm... I get the same "Variable "$foo" is not imported at ./test.pl line 12." error if I had done my $foo = "bar";. I would understand this when I use my because there is no variable $foo once we leave the block. But, our variables are suppose to be package scope. I could understand how $foo might not have a value at that point, but this?

Also, what does the "Variable "$foo" is not imported at ./test.pl line 12." mean? I understand packages and importing, but there's only a single package here, main. $foo should be in the main package. It doesn't need to be imported.

What is going on with my package variable that doesn't seem to be in the package after it falls out of scope?


Addendum

So if you used $::foo, or created another alias with our $foo; again, your program would work as expected. cmj

Let's try this...

#! /usr/bin/env perl
#
# use warnings;
use strict;
use feature qw(say);

{
    our $foo = "bar";
    say "Foo = $foo";
}

our $foo;          # Redeclared
say "Foo = $foo";  # This is line #12

Now, this prints out:

bar
bar

As everyone who answered pointed out, our merely makes an alias to the package variable of the same name, and it's lexically scoped. That means once the alias goes out of scope, so did my ability to access the value of $main::foo with $foo. That's something I never realized before.

However, as cjm pointed out, redeclaring our $foo; restores the alias, and the already existing $main::foo is aliased back to a new $foo. When I redeclare our $foo;, the value of $foo is restored.

It's one of the things about our variables that can be so confusing. You see a declaration our $foo;, and suddenly not only does that variable exist, but it has a mysterious value. You have to search the program to see where that value could have come from.

Était-ce utile?

La solution

Our declares a lexical alias to a package variable. This means that it's scoped just like my. The difference is that it's backed by a package variable, so the variable doesn't go away when you exit the scope. Only the alias goes away.

So if you used $::foo, or created another alias with our $foo again, your program would work as expected.

Autres conseils

Our does not indicate package scope.

An our declaration declares an alias for a package variable that will be visible across its entire lexical scope, even across package boundaries.

This means that when the lexical scope of the block that declared it ends, it falls out of scope.

what does the "Variable "$foo" is not imported at ./test.pl line 12." mean?

perldiag says:

With "use strict" in effect, you referred to a global variable that you apparently thought was imported from another module, because something else of the same name (usually a subroutine) is exported by that module. It usually means you put the wrong funny character on the front of your variable.

That makes no sense since you didn't import anything. It shouldn't be emitted by your code. Perl's trying to be helpful in diagnosing the strict error, but got it wrong. Ignore the warning.


But, our variables are suppose to be package scope

That's not true. our creates a lexical variable just like my. That variable is aliased to the package variable with the same name.

package Foo;
our $x;         # Equivalent to: alias my $x = $Foo::x;
$Foo::x = 123;
package Bar;
$Bar::x = 456;
print("$x\n");  # 123

(alias is provided by Data::Alias.)

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top