Beefy Boxes and Bandwidth Generously Provided by pair Networks
good chemistry is complicated,
and a little bit messy -LW
 
PerlMonks  

sharing symbols

by mungohill (Acolyte)
on Apr 13, 2007 at 09:31 UTC ( [id://609864]=perlquestion: print w/replies, xml ) Need Help??

mungohill has asked for the wisdom of the Perl Monks concerning the following question:

Dear Monks

I'm sure there must be a 'derr obvious' answer to this. What I'm trying to do is to share an evolving bunch of symbolic constants between various programs. These are just integer values with names. I was thinking I'd do it in the traditional manner of an include file.

So I had a 'do' file with the definitions. This was ok.

Bowing to peer pressure (and because it seemed like a good idea) I thought I'd introduce 'use strict' into my program. Whereupon the compiler expressed its displeasure at references in the main program to stuff defined in the 'do' file.

I thought I'd do the right thing and use a module instead, only to find that I couldn't figure out any way to export all of the symbols (for it was indeed all of them that I wanted to export) without explicitly exporting each one. This didn't appeal as I really don't like having to say things twice: it is merely an unhelpful 'opportunity to fail'. I toyed with the idea of referring in some way to the symbol table for the module but this voodoo was rather beyond me as I am ....
$_="program sign; begin writeln('really just an unreconstructed pascal hacker'); end."; s/^(..)[^i]*(.).(.)[^(]*([^;]*;).*/$1$2$3t$4/s; eval;


Thanks for all the ideas. I'm almost as gratified to see that it wasn't that obvious as I am to get the actual answer. My constants conform to /^A-Z_+$/ so I don't see having some sort of 'filtering restriction' as being too much of a problem, but I'll have to extend the list of specific exclusions. Just how many lurking hidden symbols do I need to be wary of?

Replies are listed 'Best First'.
Re: sharing symbols
by ferreira (Chaplain) on Apr 13, 2007 at 10:42 UTC

    Definitely go for the module approach. Though not that short as I would prefer, the code below demonstrate how you could achieve the effect of "automatically" stuffing your constants into the list of exports of your module.

    The code for finding the constant names in the symbol table is almost abstract and with a little effort could be migrated into a generic module, leaving your constant module lighter.

      our @GLOBAL_SYMBOLS; # these are not package constants, but Perl artif +acts BEGIN { @GLOBAL_SYMBOLS = qw(BEGIN EXPORT); }
      sub is_constant { my $k = shift; return $k =~ /^[A-Z]+$/ && !grep { $_ eq $k } @GLOBAL_SYMBOLS }
      Bah, use a hash, Luke! Use a hash!
      our %GLOBAL_SYMBOL; # these are not package constants, but Perl artifa +cts BEGIN { %GLOBAL_SYMBOL = map { $_ => 1 } qw(BEGIN EXPORT ISA EXPORT_OK GLO +BAL_SYMBOL); }
      sub is_constant { my $k = shift; return $k =~ /^[A-Z_0-9]+$/ && !$GLOBAL_SYMBOL{$k}; }

      BTW did you forget to exclude @GLOBAL_SYMBOLS, by any chance? And, why not use a lexical for it?

      BTW I think this functionality is generally interesting enough to deserve its own module on CPAN. Let's call it ExportAll, or something else like that. And, as the helper subs would reside in that module, they wouldn't be exported themselves.

      Update: Oh no, I see you only support only upper case letters only names (which would exclude @GLOBAL_SYMBOLS). Which seems too restrictive to my taste.

        Oh no, I see you only support only upper case letters only names (which would exclude @GLOBAL_SYMBOLS). Which seems too restrictive to my taste.

        Don't go down on me that fast. This restriction can be lifted very easily and that's why I kept is_constant separated from push_constants. If the role of is_constant is taken by a subroutine ref, the rest is generic enough.

        Here an implementation of that generic module whose idea you cherished for a moment:

        And then applying it to the original request of the OP: The user's code just says
        use MyConstants;
        to import the constants into the current namespace.

        BTW I have not worried with @GLOBAL_SYMBOLS because it didn't match /^[A-Z]+$/ which does not accept underlines. It was an oversight, but, because of this, it was not a problem.

        BTW you were right about using a hash. The grep was only for a quick-and-dirty solution.

Re: sharing symbols
by cdarke (Prior) on Apr 13, 2007 at 11:02 UTC
    I like ferreira's approach better than mine, but, in the spirit of tmtowtdi, here it is anyway:
    package myfile; use strict; use Exporter; our @ISA = qw(Exporter); # Setup the variables with values my $list = 'our $myvar = 42; our $another = 1234; our $yascalar = 3456;'; eval $list; $list =~ s/our (.+?)\s+= \d+;/$1/g; our @EXPORT = split("\n", $list); 1;

    Not nice, but it works. Be particularly careful about whitespace when declaring the variables, it may affect the RE.
Re: sharing symbols
by almut (Canon) on Apr 13, 2007 at 16:15 UTC

    In case you'd (only) use the pragma constant to declare your constants, you could use its hash %constant::declared to get the list of names to export. Something like this

    Your module with the constants:

    package MyConsts; use constant { CONST1 => 123, CONST2 => 1.11, CONST3 => "foo", CONST4 => ["foo", "bar"], }; use constant CONST5 => qw(foo bar); use Exporter 'import'; our @EXPORT = map /([^:]+)$/, keys %constant::declared; 1;

    How to make use of it:

    #!/usr/bin/perl use strict; use warnings; use MyConsts; print CONST1, "\n"; # or some weirder cases (just to illustrate, # I understand that you only need integers) print "@{CONST4()}\n"; # -> foo bar print "@{[CONST5]}\n"; # -> foo bar print +(CONST5)[1], "\n"; # -> bar
Re: sharing symbols
by Krambambuli (Curate) on Apr 13, 2007 at 10:41 UTC
    I'm not at all sure there is an 'derr obvious' answer to your problem - right on the contrary.

    I think you'll have to go another way; consider for example changing your programs to explicitely use
    use SHARED_INTEGERS; my $calculation = $SHARED_INTEGERS::alfa * $SHARED_INTEGERS::beta;
    where you'd have an module named SHARED_INTEGERS.pm that would export _nothing_ but might look like
    package SHARED_INTEGERS.pm $alfa = 123; $beta = 456;
    I know it's rather in the opposite direction that you are looking for - still, maybe it's worth thinking once more about the pros and cons of the different approaches.
    Maybe you could also consider the constant pragma.
Re: sharing symbols
by mungohill (Acolyte) on Apr 13, 2007 at 14:17 UTC
    Thanks for the ideas.

    It has at least allowed me to clarify some of my ideas about this.
    Nothing actually gives me what I want, but I can see that what I wanted violated the sanctity of 'use strict'. I was explicitly wanting to be able to make implicit references to symbols in another package. Terrible thing thoughtcrime.

    What it looks like to me is that there isn't any way when you use strict 'vars' to provide definitions that look as though they are in your namespace unless they are physically in your file.

    It's this kind of thing that makes people consider options like no strict 'vars' or even (horror of horrors) pre-processing.

    Is there some sort of non-righteousness in the laziness of not wanting to qualify these symbols with package names?

Log In?
Username:
Password:

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

How do I use this?Last hourOther CB clients
Other Users?
Others taking refuge in the Monastery: (4)
As of 2024-04-19 07:04 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found