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

Simple question, complex situation.
I'm trying to have a routine that will populate a package with a "default" set of data.
Naturally, the normal way to do this would be to bless the data and create a class. However, due to legacy reasons, I need an actual package with "normally" defined variables and subroutines.
Basic Summary:
$name='Foo'; &populate($name); #If someone figures out an OO method of this, that' +s fine too #package Foo now has the default values $::oldpackage=$__PACKAGE__; package $name; #Change it from the defaults $bar='baz'; package $::oldpackage; #continue on with the program, now that Foo has all the data I want.
This psuedo-code has many problems though, and I'm a long way from making it reality. Can anyone help me figure this out?

Replies are listed 'Best First'.
Re: Variable Package Names?
by chromatic (Archbishop) on Aug 14, 2000 at 21:10 UTC
    Here's an answer that shows why I like eval -- not because it's efficient, safe, or even clean, but because you can occasionally throw off the shackles of other computer languages and do stuff at runtime you'd never thought possible.

    Warning: This is almost definitely not the best way to approach your problem, and if you use it in production code you're more courageous than I -- but it's a tool and I know how to do it. Sufficiently warned:

    #!/usr/bin/perl -w use strict; BEGIN { my @packages = qw(test test2); my @vars = qw(first second); populate(); sub populate { my $text = ''; foreach my $package (@packages) { foreach my $var (@vars) { $text = '$' . $package . '::' . $var . ' = 1;' . "\n"; print $text; eval $text; } } } } print "test:\t$test::first\t$test::second\n"; print "test2:\t$test2::first\t$test2::second\n";
    You could also create $text to eval that contains your package statement and use vars statements or my statements as you see fit.

    There's another way, using symbolic references. That's also generally considered a bad idea, because it's easy to cause flaming death with a typo:

    #!/usr/bin/perl -w use strict; my @vars = qw(one two three); package main; my ($one, $two, $three) = (1 .. 3); { no strict 'refs'; foreach my $var (@vars) { *{"test::$var"} = $var; } } package test; print "One: $one\tTwo: $two\tThree: $three\n";
Re: Variable Package Names?
by merlyn (Sage) on Aug 14, 2000 at 20:54 UTC
    The "package" is determined strictly at compile time. First, I'll rant about wanting to mix code and data, a great source of security holes if not also a horrible maintainance headache (what if they ask for "main" as the package to import their variables!?). Having said that, one option is to do as the Exporter does with the import routine, messing with globs to copy values. Ewww. Much smoke, many mirrors.

    -- Randal L. Schwartz, Perl hacker

      First, I'll rant about wanting to mix code and data

      Well, I'm not really trying to mix data, so much as providing the programmer with options. The Package name is variable purely so that the programmer can create multiple copies of the same dataset. It should never be selected from using data, same as one shouldn't have "soft" references from data either.

      what if they ask for "main" as the package to import their variables!?

      I would hope it would create a bunch of variables in main. Yes, this would trample any existing variables of the same name, but that's why the programmer should know what names the script is being called on :)

      Having said that, one option is to do as the Exporter does with the import routine, messing with globs to copy values.

      I was afraid that might be the answer. Thanks.

Re: Variable Package Names?
by Hot Pastrami (Monk) on Aug 14, 2000 at 23:06 UTC
    If you consider using chromatic's first idea, I'd suggest that you re-work it like so:
    #!/usr/bin/perl -w use strict; BEGIN { my @packages = qw(test test2); my @vars = qw(first second); populate(); sub populate { my $text = ''; foreach my $package (@packages) { foreach my $var (@vars) { $text .= '$' . $package . '::' . $var . ' = 1;' . "\n" +; } } print $text; eval $text; } } print "test:\t$test::first\t$test::second\n"; print "test2:\t$test2::first\t$test2::second\n";
    ... this way, you move the eval() outside the loop, which I understand improves performance significantly.

    Alan "Hot Pastrami" Bellows
    -Sitting calmly with scissors-