Constants across package boundaries

B

bernie

I've been chasing a compile problem and I just saw the light on what
my trouble is: I use a bunch of "use constant this => ...; use
constant that =>...;" to set parameters for the program. BUT: the
program uses a 'package' or two [it has a small embedded objects in
it]. The trouble is that the package can't access the 'constant' --
that section of the program gets [not surprisingly] bareword errors.
I can fix them by using "main::..." but that's really ugly. Is there
any really clean way to set up truly "global" constants? Thanks!

/Bernie\
 
J

Joost Diepenmaat

I've been chasing a compile problem and I just saw the light on what
my trouble is: I use a bunch of "use constant this => ...; use
constant that =>...;" to set parameters for the program. BUT: the
program uses a 'package' or two [it has a small embedded objects in
it]. The trouble is that the package can't access the 'constant' --
that section of the program gets [not surprisingly] bareword errors.
I can fix them by using "main::..." but that's really ugly. Is there
any really clean way to set up truly "global" constants? Thanks!

I think you'd rather just export the constants to any package that
needs them, instead of making them truly global (which would be more
or less equivalent to exporting them to *all* packages)

See perldoc Exporter.
 
B

bernie

I've been chasing a compile problem  and I just saw the light on what
my trouble is: I use a bunch of "use constant this => ...; use
constant that =>...;" to set parameters for the program.  BUT: the
program uses a 'package' or two [it has a small embedded objects in
it].

I note that this is documented on the 'constant' man page. Sigh. I
guess I could just use ::THIS and ::that but that feels a bit
inelegant...
I think you'd rather just export the constants to any package that
needs them, instead of making them truly global (which would be more
or less equivalent to exporting them to *all* packages)

Can you export from main *to* a package? Using Exporter in this way
looks like it is a little confusing (it might become clearer after
another six readings of the man page..:eek:)). I guess I could do
something along the lines of putting require Exporter in my main
program, setting up @EXPORT_OK in the main program the "constants" I
want the interior packages to be able to import, and then do
a ::import(stuff I need) after the 'package' for the interior object-
section? You're right: that kind of approach would make the interior
packages be more self-contained and clearer (by making explicit that
they're pulling in those vbls from "main::")

OTOH, I see that there's a "Readonly" package that looks like it will
do what I was originally trying to do ["Readonly \my $CONST => val"
generates a real cross-package constant]. [although now that I see a
way to do what I originally wanted, I'm not so sure it is as clean a
way to go as I'd like...:(]

Thanks...

/Bernie\
 
B

bernie

...  I guess I could do
something along the lines of putting require Exporter in my main
program, setting up @EXPORT_OK in the main program the "constants" I
want the interior packages to be able to import, and then do
a ::import(stuff I need) after the 'package' for the interior object-
section?

I'm running down this path to see how it looks and feels to properly
export and import my "global" constants. And I've run into a
problem. The man page for Exporter says:

package YourModule;
use Exporter 'import'; # gives you Exporter's import() method
directly
@EXPORT_OK = qw(munge frobnicate); # symbols to export on request

But in my code I have:
--------------------------
#!/usr/bin/perl

use strict ;
use warnings ;

use Exporter 'import' ;
our @ISA = qw(Exporter);
use constant AAA => 4 ;
our @EXPORT_OK = ('AAA') ;
----------------------------

"import" is not exported by the Exporter module at test.pl line 6

I can't figure out quite what I'm doing wrong... And then I'm
guessing that down in the program in my package I'd do:
package MYPACKAGE;
::import(qw(constants I want))

/Bernie\
 
T

Ted Zlatanov

On Tue, 13 May 2008 05:36:40 -0700 (PDT) (e-mail address removed) wrote:

b> I've been chasing a compile problem and I just saw the light on what
b> my trouble is: I use a bunch of "use constant this => ...; use
b> constant that =>...;" to set parameters for the program. BUT: the
b> program uses a 'package' or two [it has a small embedded objects in
b> it]. The trouble is that the package can't access the 'constant' --
b> that section of the program gets [not surprisingly] bareword errors.
b> I can fix them by using "main::..." but that's really ugly. Is there
b> any really clean way to set up truly "global" constants? Thanks!

This may be possible with some advanced wizardry or source filtering.
You could also fake it like this:

#!/usr/bin/perl

use warnings;
use strict;

use constant GLOBAL => 'global';

package test;

use constant LOCAL => main::GLOBAL; # can also be called GLOBAL

print LOCAL, "\n";

but it's probably easiest if you set up a 'constants' package that
exports the right things, and import it into each package that needs it.

I'm sure there's better ways :)

Ted
 
B

Ben Morrow

Quoth (e-mail address removed):
It's probably a bad idea to export from main::. I'd define a separate
package for your constants, and 'use' it from everywhere else.
I'm running down this path to see how it looks and feels to properly
export and import my "global" constants. And I've run into a
problem. The man page for Exporter says:

package YourModule;
use Exporter 'import'; # gives you Exporter's import() method
directly
@EXPORT_OK = qw(munge frobnicate); # symbols to export on request

But in my code I have:
--------------------------
#!/usr/bin/perl

use strict ;
use warnings ;

use Exporter 'import' ;
our @ISA = qw(Exporter);
use constant AAA => 4 ;
our @EXPORT_OK = ('AAA') ;

Does the manpage you're using match your version of Exporter? The
ability to import (rather than inherit) Exporter::import was not present
in older versions of Exporter.

Ben
 
T

Thomas Kratz

I've been chasing a compile problem and I just saw the light on what
my trouble is: I use a bunch of "use constant this => ...; use
constant that =>...;" to set parameters for the program. BUT: the
program uses a 'package' or two [it has a small embedded objects in
it]. The trouble is that the package can't access the 'constant' --
that section of the program gets [not surprisingly] bareword errors.
I can fix them by using "main::..." but that's really ugly. Is there
any really clean way to set up truly "global" constants? Thanks!

Not clean nor elegant but works for simple (not array or hash) constants
by feeding the constants from main again to 'use constants':

test.pl:

use strict;
use warnings;
use constant BLA => 5;
use Mod;
print Mod::Sub1();

Mod.pm

package Mod;
use strict;
use warnings;

my %const;
BEGIN {
%const = map {
(my $name = $_) =~ s/^main:://;
no strict 'refs';
$name => &$_();
} grep {
/^main::/
} keys %constant::declared;
}

use constant \%const;

sub Sub1 { return BLA; }

1;

Thomas

--
$/=$,,$_=<DATA>,s,(.*),$1,see;__END__
s,^(.*\043),,mg,@_=map{[split'']}split;{#>J~.>_an~>>e~......>r~
$_=$_[$%][$"];y,<~>^,-++-,?{$/=--$|?'"':#..u.t.^.o.P.r.>ha~.e..
'%',s,(.),\$$/$1=1,,$;=$_}:/\w/?{y,_, ,,#..>s^~ht<._..._..c....
print}:y,.,,||last,,,,,,$_=$;;eval,redo}#.....>.e.r^.>l^..>k^.-
 
A

A. Sinan Unur

(e-mail address removed) wrote in (e-mail address removed):
I've been chasing a compile problem and I just saw the light on what
my trouble is: I use a bunch of "use constant this => ...; use
constant that =>...;" to set parameters for the program. BUT: the
program uses a 'package' or two [it has a small embedded objects in
it]. The trouble is that the package can't access the 'constant' --
that section of the program gets [not surprisingly] bareword errors.
I can fix them by using "main::..." but that's really ugly. Is there
any really clean way to set up truly "global" constants? Thanks!

The proper way to do this would be to set up a package for all your
constants and use it from any file that needs any of those constants.

Keep in mind that constants defined using the constant pragma are not
variables but subroutines.

In any case, here is how to do it:

E:\Home\asu1\Src\Test> cat My\Constants.pm
package My::Constants;

use strict;
use warnings;

use base qw( Exporter );

our @EXPORT = qw();
our @EXPORT_OK = qw( ONE TWO THREE );

use constant ONE => 'one';
use constant TWO => 'two';
use constant THREE => 'three';

1;

E:\Home\asu1\Src\Test> cat My\Util.pm
package My::Util;

use strict;
use warnings;

use My::Constants qw( ONE TWO THREE );

sub some_func { join( "\t", ONE, TWO, THREE ) }

1;

E:\Home\asu1\Src\Test> cat C.pl
#!/usr/bin/perl

use strict;
use warnings;

use My::Constants qw( ONE TWO THREE );
use My::Util;

print "$_\n" for ONE, TWO, THREE, My::Util::some_func;

__END__

E:\Home\asu1\Src\Test> C
one
two
three
one two three


--
A. Sinan Unur <[email protected]>
(remove .invalid and reverse each component for email address)

comp.lang.perl.misc guidelines on the WWW:
http://www.rehabitation.com/clpmisc/
 
T

Thomas Kratz

A. Sinan Unur said:
package My::Constants;

use strict;
use warnings;

use base qw( Exporter );

our @EXPORT = qw();
our @EXPORT_OK = qw( ONE TWO THREE );

use constant ONE => 'one';
use constant TWO => 'two';
use constant THREE => 'three';

1;

I just needed that last week for a module but found the:

our @EXPORT_OK = qw( ONE TWO THREE );

a bit tedious when you are having many constants. I had to play around a
bit and found you can do (maybe that's obvious, but it wasn't to me):

my %constant_hash;
BEGIN {
%constant_hash = (
ONE => 'one',
TWO => 'two',
THREE => 'three',
};
}
our @EXPORT_OK = keys %constant_hash;
our %EXPORT_TAGS = (
constants => [keys %constant_hash],
);

Thomas

--
$/=$,,$_=<DATA>,s,(.*),$1,see;__END__
s,^(.*\043),,mg,@_=map{[split'']}split;{#>J~.>_an~>>e~......>r~
$_=$_[$%][$"];y,<~>^,-++-,?{$/=--$|?'"':#..u.t.^.o.P.r.>ha~.e..
'%',s,(.),\$$/$1=1,,$;=$_}:/\w/?{y,_, ,,#..>s^~ht<._..._..c....
print}:y,.,,||last,,,,,,$_=$;;eval,redo}#.....>.e.r^.>l^..>k^.-
 
B

Ben Morrow

Quoth Thomas Kratz said:
A. Sinan Unur said:
package My::Constants;

use strict;
use warnings;

use base qw( Exporter );

our @EXPORT = qw();
our @EXPORT_OK = qw( ONE TWO THREE );

use constant ONE => 'one';
use constant TWO => 'two';
use constant THREE => 'three';

1;

I just needed that last week for a module but found the:

our @EXPORT_OK = qw( ONE TWO THREE );

a bit tedious when you are having many constants. I had to play around a
bit and found you can do (maybe that's obvious, but it wasn't to me):

my %constant_hash;
BEGIN {
%constant_hash = (
ONE => 'one',
TWO => 'two',
THREE => 'three',
};
}
our @EXPORT_OK = keys %constant_hash;
our %EXPORT_TAGS = (
constants => [keys %constant_hash],
);

There's no need for the BEGIN block: since this is a 'use'd module,
everything will happen at BEGIN time anyway.

require constant;

my %constants = (
ONE => 'one',
TWO => 'two',
);

our (@EXPORT_OK, %EXPORT_TAGS);

for (keys %constants) {
constant->import($_ => $constants{$_});
push @{ %EXPORT_TAGS{constants} }, $_;
}
push @EXPORT_OK, @{ %EXPORT_TAGS{constants} };

Ben
 
A

A. Sinan Unur

I just needed that last week for a module but found the:

our @EXPORT_OK = qw( ONE TWO THREE );

a bit tedious when you are having many constants. I had to play around
a bit and found you can do (maybe that's obvious, but it wasn't to
me):

my %constant_hash;
BEGIN {
%constant_hash = (
ONE => 'one',
TWO => 'two',
THREE => 'three',
};

Ooops, s/}/)/ ;-)
}
our @EXPORT_OK = keys %constant_hash;
our %EXPORT_TAGS = (
constants => [keys %constant_hash],
);

To avoid having to type the use constant statements as well, you need
something along the lines of

BEGIN {

# see above for %constant_hash

for my $k ( keys %constant_hash ) {
no strict 'refs';
*{ "My::Constants::$k" } = sub { $constant_hash{ $k } };
}
};


Sinan

--
A. Sinan Unur <[email protected]>
(remove .invalid and reverse each component for email address)

comp.lang.perl.misc guidelines on the WWW:
http://www.rehabitation.com/clpmisc/
 
T

Thomas Kratz

A. Sinan Unur said:
Ooops, s/}/)/ ;-)

I really should use a bigger font in my newsreader :)
}
our @EXPORT_OK = keys %constant_hash;
our %EXPORT_TAGS = (
constants => [keys %constant_hash],
);

To avoid having to type the use constant statements as well, you need
something along the lines of

BEGIN {

# see above for %constant_hash

for my $k ( keys %constant_hash ) {
no strict 'refs';
*{ "My::Constants::$k" } = sub { $constant_hash{ $k } };
}
};

Ah No! I forgot the most important line in my post :-(
You can simply do a:

use constant \%constant_hash;

right after the BEGIN block. That was the reason for creating the hash
in the first place. I should have run the code after extracting it from
the module.

Thomas

--
$/=$,,$_=<DATA>,s,(.*),$1,see;__END__
s,^(.*\043),,mg,@_=map{[split'']}split;{#>J~.>_an~>>e~......>r~
$_=$_[$%][$"];y,<~>^,-++-,?{$/=--$|?'"':#..u.t.^.o.P.r.>ha~.e..
'%',s,(.),\$$/$1=1,,$;=$_}:/\w/?{y,_, ,,#..>s^~ht<._..._..c....
print}:y,.,,||last,,,,,,$_=$;;eval,redo}#.....>.e.r^.>l^..>k^.-
 
T

Thomas Kratz

Ben said:
Quoth Thomas Kratz said:
A. Sinan Unur said:
package My::Constants;

use strict;
use warnings;

use base qw( Exporter );

our @EXPORT = qw();
our @EXPORT_OK = qw( ONE TWO THREE );

use constant ONE => 'one';
use constant TWO => 'two';
use constant THREE => 'three';

1;
I just needed that last week for a module but found the:

our @EXPORT_OK = qw( ONE TWO THREE );

a bit tedious when you are having many constants. I had to play around a
bit and found you can do (maybe that's obvious, but it wasn't to me):

my %constant_hash;
BEGIN {
%constant_hash = (
ONE => 'one',
TWO => 'two',
THREE => 'three',
};
}
our @EXPORT_OK = keys %constant_hash;
our %EXPORT_TAGS = (
constants => [keys %constant_hash],
);

There's no need for the BEGIN block: since this is a 'use'd module,
everything will happen at BEGIN time anyway.

require constant;

my %constants = (
ONE => 'one',
TWO => 'two',
);

our (@EXPORT_OK, %EXPORT_TAGS);

for (keys %constants) {
constant->import($_ => $constants{$_});
push @{ %EXPORT_TAGS{constants} }, $_;
}
push @EXPORT_OK, @{ %EXPORT_TAGS{constants} };

You are right if you call constant->import. I think for using

use constant \%constants;

%constants must be filled in a BEGIN block.

Thomas

--
$/=$,,$_=<DATA>,s,(.*),$1,see;__END__
s,^(.*\043),,mg,@_=map{[split'']}split;{#>J~.>_an~>>e~......>r~
$_=$_[$%][$"];y,<~>^,-++-,?{$/=--$|?'"':#..u.t.^.o.P.r.>ha~.e..
'%',s,(.),\$$/$1=1,,$;=$_}:/\w/?{y,_, ,,#..>s^~ht<._..._..c....
print}:y,.,,||last,,,,,,$_=$;;eval,redo}#.....>.e.r^.>l^..>k^.-
 
B

Ben Morrow

Quoth Bernie Cosell said:
Is there a way to do this *locally*, in the same file. That is, at the
start of my .pl file, I had just a block of:

use constant THIS => xxx;
use constant THAT => yyy;
...

It is no problem at all making that:
{ package constants ;
use Exporter ;
our EXPORT_OK(qw(THIS THAT THEOTHER)) ;
use constant THIS =>
...etc.
}
but how would I then "import" that package's exports into my main program
and into the one or two "package regions" in it? Can I just later on do
constants::import(qw(var1 var2 var3));
???

I would do it like this:

BEGIN {
package My::Constants; # don't use all-lowercase package names:
# they are reserved for pragmata

$INC{'My/Constants.pm'} = $0; # tell perl we've loaded this
# module

use Exporter;
our @EXPORT_OK = ...;

use constant ...;
}

use My::Constants qw/foo bar baz/;

Setting the entry in $INC (at compile time) means that 'use' now just
performs an import at compile time.

Alternatively, yes,

BEGIN { My::Constants->import(qw/foo bar/) }

will work perfectly well (note that import is a *method*, not a
function).

Ben
 
C

comp.llang.perl.moderated

Quoth Bernie Cosell <[email protected]>:








I would do it like this:

BEGIN {
package My::Constants; # don't use all-lowercase package names:
# they are reserved for pragmata

$INC{'My/Constants.pm'} = $0; # tell perl we've loaded this
# module

use Exporter;
^^^^^^^^^^^^^

Er, you'd be better off with one of these to ensure the import happens
though right... :)


use Exporter qw/import/;
# our @ISA = qw/Exporter/;
 

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,769
Messages
2,569,580
Members
45,054
Latest member
TrimKetoBoost

Latest Threads

Top