`our' declaration causing problems with `strict' pragma across files

D

Dave Bakhash

I have a set of executable scripts, all written in Perl. This time,
however, I would like all of these scripts to obtain their globals
from a single, separate file. I would also like all of my Perl files
to use the `strict' pragma:

use strict;

which has been a requirement of mine since I started using Perl.

Here's how I thought to do it. Suppose I have a script, foo:

File: foo

#!/usr/bin/perl
package Foo;
use strict;
BEGIN { require "/path/to/Foo.pm"; }

print $BAR; # uses a global variable `$BAR' defined in Foo.pm

# code follows...

Now, the file Foo.pm will look like this:

File: Foo.pm

package Foo;
use strict;
our $BAR = 'BAR'; # global variable
1;

The problem is that having the `use strict;' in the `foo' executable
file is causing problems, and Perl is complaining:

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

What am I missing? Is there a better way to do this? Is `our' the
wrong declaration to be using here?

thanks,
dave
 
A

Anno Siegel

Dave Bakhash said:
I have a set of executable scripts, all written in Perl. This time,
however, I would like all of these scripts to obtain their globals
from a single, separate file. I would also like all of my Perl files
to use the `strict' pragma:

use strict;

which has been a requirement of mine since I started using Perl.

Here's how I thought to do it. Suppose I have a script, foo:

File: foo

#!/usr/bin/perl
package Foo;
use strict;
BEGIN { require "/path/to/Foo.pm"; }

"BEGIN { require ... } is nearly equivalent to "use".
print $BAR; # uses a global variable `$BAR' defined in Foo.pm

# code follows...

Now, the file Foo.pm will look like this:

File: Foo.pm

package Foo;
use strict;
our $BAR = 'BAR'; # global variable
1;

The problem is that having the `use strict;' in the `foo' executable
file is causing problems, and Perl is complaining:

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

What am I missing? Is there a better way to do this? Is `our' the
wrong declaration to be using here?

"our" is block scoped, which means its scope can't be bigger than the
file it appear in. You'd need another "our" declaration in every file
that uses the variable.

The standard method to do what you want is exportation. Put this in
Foo.pm:

package Foo;
use strict; use warnings;

use Exporter;
our @ISA = qw/Exporter/;
our @EXPORT = qw/$my_var/;

our $my_var;
$my_var = 123;

1;

and this in Foo:

#!/usr/local/bin/perl
use strict; use warnings; $| = 1;

use MyLib;

print "$my_var\n";

For the details, see "perldoc Exporter".

Anno
 
B

Brian McCauley

Foo.pm:

package Foo;
use strict; use warnings;

use Exporter;
our @ISA = qw/Exporter/;
our @EXPORT = qw/$my_var/;

our $my_var;
$my_var = 123;

1;
and this in Foo:

#!/usr/local/bin/perl
use strict; use warnings; $| = 1;

use MyLib;

s/MyLib/Foo/

--
\\ ( )
. _\\__[oo
.__/ \\ /\@
. l___\\
# ll l\\
###LL LL\\
 
B

Ben Morrow

Quoth (e-mail address removed) (Dave Bakhash):
I have a set of executable scripts, all written in Perl. This time,
however, I would like all of these scripts to obtain their globals
from a single, separate file. I would also like all of my Perl files
to use the `strict' pragma:

use strict;

which has been a requirement of mine since I started using Perl.

Good. You want

use warnings;

as well: read perldoc warnings for how to temporarily turn off warnings
you know are harmless.
Here's how I thought to do it. Suppose I have a script, foo:

File: foo

#!/usr/bin/perl
package Foo;
use strict;
BEGIN { require "/path/to/Foo.pm"; }

use Foo;

is better; and you should probably call it Local::Foo or MyApp::Foo or
something to avoid conflict with a CPAN module.
print $BAR; # uses a global variable `$BAR' defined in Foo.pm

No it doesn't. The global variable in Foo.pm is called $Foo::BAR, as you
were in package Foo at the time. Read perlmod. If you want to be able to
refer to $Foo::BAR as $BAR in your main script, you can 'import' it: for
this, see perldoc Exporter or any of the replacements on CPAN.
What am I missing? Is there a better way to do this? Is `our' the
wrong declaration to be using here?

'our' is exactly the right declaration to be using. You just need to
know what your variable is called once you've declared it :).

Ben
 
C

ctcgag

I have a set of executable scripts, all written in Perl. This time,
however, I would like all of these scripts to obtain their globals
from a single, separate file. I would also like all of my Perl files
to use the `strict' pragma:

use strict;

which has been a requirement of mine since I started using Perl.

Here's how I thought to do it. Suppose I have a script, foo:

File: foo

#!/usr/bin/perl
package Foo;
use strict;
BEGIN { require "/path/to/Foo.pm"; }

print $BAR; # uses a global variable `$BAR' defined in Foo.pm

# code follows...

Now, the file Foo.pm will look like this:

File: Foo.pm

package Foo;
use strict;
our $BAR = 'BAR'; # global variable
1;

Others have told you how to have Foo export variables into the using
package's name space. I would like to urge you to consider another
solution, which is to fully specify the variable name:

print $Foo::Bar;

The downside of this is that you have to type "Foo::" for each use of those
global variable, which is not much of a downside unless the variables are
used quite extensively. The upside is that it is much easier to remember
where to look for that variable declaration (which, if you use the variable
extensively, is probably hard to forget, but if it used just a few times,
is easy to forget). This explicitness is especially important if the code
will be maintained by others not intimately familiar with it.

Xho
 
A

Anno Siegel

Peter Scott said:
Except that use won't accept a string like that, the argument has to be a
bareword...

True. I should have known that trying to gloss over that wouldn't work :)

Anno
 
D

Dave Bakhash

Others have told you how to have Foo export variables into the using
package's name space. I would like to urge you to consider another
solution, which is to fully specify the variable name:

print $Foo::Bar;

Yeah...well, the thing is that I come from this Common Lisp background,
where we also have packages (i.e. namespaces), and so when two files are
in the same package, their variables should naturally be in that package
by default, so if a variable is defined in one file, it should be
available to another without warnings.

It seems almost as if Perl is making this arbitrary exception just
because the variables are being used across file boundaries, which I'm
not used to.

I don't want to use the Exporter stuff because the whole point is that
the two files are in the *same* package. I just want them to be
shared.

I think the 'use vars ...' stuff would have worked, but I just figured
I'd do:

use strict;
no strict 'vars';

and to hell with trying to appease Perl. God...all these years, and I
still can't say I fully understand `our'.

dave
 
P

Paul Lalli

Yeah...well, the thing is that I come from this Common Lisp background,
where we also have packages (i.e. namespaces), and so when two files are
in the same package, their variables should naturally be in that package
by default, so if a variable is defined in one file, it should be
available to another without warnings.

It seems almost as if Perl is making this arbitrary exception just
because the variables are being used across file boundaries, which I'm
not used to.

I don't want to use the Exporter stuff because the whole point is that
the two files are in the *same* package. I just want them to be
shared.

I'm not sure if the other responders noticed the whole 'same package' deal
or not.... this works for me:

File: temp.pl
#!/usr/bin/env perl
use strict;
use warnings;

use Foo;

package Foo;
our $bar;
print "Explicit: $Foo::bar\n";
print "Implicit: $bar\n";
__END__

File: Foo.pm
package Foo;
use strict;
our $bar = 'Hello World';

1;



Both print statements output "Hello World\n"; Is that what you're
looking for?


Paul Lalli
 
U

Uri Guttman

DB> and to hell with trying to appease Perl. God...all these years, and I
DB> still can't say I fully understand `our'.

it is much simpler than you realize. it just creates a short nickname in
the current lexical or file scope for a package variable. in some ways
it is just a lexical version of user 'vars'. so you can do our $foo in
two separate files which are in the same package and both $foo's refer
to the same package variable. it also means that fully qualified access
to $foo is still possible.

uri
 
A

Anno Siegel

Uri Guttman said:
DB> and to hell with trying to appease Perl. God...all these years, and I
DB> still can't say I fully understand `our'.

it is much simpler than you realize. it just creates a short nickname in
the current lexical or file scope for a package variable. in some ways
it is just a lexical version of user 'vars'. so you can do our $foo in
two separate files which are in the same package and both $foo's refer
to the same package variable. it also means that fully qualified access
to $foo is still possible.

It also means that "our" isn't really a declaration, in the sense that
it tells the compiler you are going to use that variable. Package
variables don't need one, the first usage is implicitly also the
declaration. "our" only enables a shortcut. If it declares anything,
it's the lexical alias (which you're not supposed to know about).

In contrast, a lexical variable is actually created by the "my" statement.
The parallelism between "my" and "our" is really bogus on a deep level,
though superficially the rule 'declare lexicals with "my", package
variables with "our"' works well enough.

Two fundamentally different mechanisms work in tandem to let you deal
with package variables just like with lexicals, even under strict. I
liken it with a sculpture where two wildly different shapes surprisingly
show the same profile from one point of view. In the Perl case, that's
the viewpoint of the casual user. Once you leave that point, the
different structure of "my" and "our" becomes obvious.

That kind of mental shape-shifting can be bewildering, but it's one of
those things that make Perl what it is.

Anno
 
U

Uri Guttman

AS> It also means that "our" isn't really a declaration, in the sense
AS> that it tells the compiler you are going to use that variable.
AS> Package variables don't need one, the first usage is implicitly
AS> also the declaration. "our" only enables a shortcut. If it
AS> declares anything, it's the lexical alias (which you're not
AS> supposed to know about).

for some definition of 'declaration' :)

AS> In contrast, a lexical variable is actually created by the "my"
AS> statement. The parallelism between "my" and "our" is really bogus
AS> on a deep level, though superficially the rule 'declare lexicals
AS> with "my", package variables with "our"' works well enough.

which was my point. it gets around strict without needing fully
qualified names or use vars which had file scoping.

AS> Two fundamentally different mechanisms work in tandem to let you
AS> deal with package variables just like with lexicals, even under
AS> strict. I liken it with a sculpture where two wildly different
AS> shapes surprisingly show the same profile from one point of view.
AS> In the Perl case, that's the viewpoint of the casual user. Once
AS> you leave that point, the different structure of "my" and "our"
AS> becomes obvious.

but the surface is all that most coders need to know here. so my
description was fine for the poster who never got 'our'. and to make
him feel better it took me a long time to understand it too. it is not
well described in the docs. the whole idea of calling it a lexical
nickname/alias for a package variable is what cleared it up for me.

uri
 
A

Anno Siegel

["my" and "our"]
AS> Two fundamentally different mechanisms work in tandem to let you
AS> deal with package variables just like with lexicals, even under
AS> strict. I liken it with a sculpture where two wildly different
AS> shapes surprisingly show the same profile from one point of view.
AS> In the Perl case, that's the viewpoint of the casual user. Once
AS> you leave that point, the different structure of "my" and "our"
AS> becomes obvious.

but the surface is all that most coders need to know here. so my
description was fine for the poster who never got 'our'.

Oh, sure... I didn't mean to say your explanation was lacking. I
thought it could use some background, for those interested.
and to make
him feel better it took me a long time to understand it too.

Me too, as they, allegedly, say on AOL.
it is not
well described in the docs. the whole idea of calling it a lexical
nickname/alias for a package variable is what cleared it up for me.

It clears it up, because it explains what is happening in the familiar
terms of lexical variables and their scope, plus the notion of an alias.

That's why I agree, the doc should explain it that way, instead of
beating around the bush with

the same scoping rules as a "my" declaration, but does not cre-
ate a local variable. ...

and

visible across its entire lexical scope, even across package
boundaries. ...

Calling a lexical alias a lexical alias (with a few more words) would
make this and more stuff mere consequences which are to be expected.

Of course, here comes the point where someone gets to mention that
even doc patches speak louder than words.

Anno
 
B

Brian McCauley

True. I should have known that trying to gloss over that wouldn't work :)

Usually one would do something like:

use lib '/path/to';
use Foo;

Or

BEGIN { require '/path/to/Foo.pl' }

It is IMNSO confusing to use .pm suffix (usually associated with Perl5
modules) for something that's loaded like a Perl4-style library.

--
\\ ( )
. _\\__[oo
.__/ \\ /\@
. l___\\
# ll l\\
###LL LL\\
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,764
Messages
2,569,564
Members
45,039
Latest member
CasimiraVa

Latest Threads

Top