dynamically creating a hash from an array

Discussion in 'Perl Misc' started by ccc31807, Mar 21, 2014.

  1. ccc31807

    ccc31807 Guest

    To be honest, this may be a FAQ, but I don't seem to have the vocabulary to find it.

    Suppose I have a set of variables, like this:
    my $username = 'Joe';
    my $password = 'somepassword';
    my $role = 'user';
    my $session = 'q1w2e3r4t5y6';
    my $date = '2014-03-21';
    my $time = '12345678';

    Now, suppose I have a sub that prints the name and value of each variable, like this:
    sub debug
    {
    my $href = shift;
    print "-------------begin debugging data------------\n";
    foreach my $key (sort keys %{$href})
    {
    print "$key = $href->{$key}\n";
    }
    print "-------------end debugging data------------\n";
    }

    Further, suppose I have an array, like this:
    my @debugarray = qw( username password role session date time );

    Question: how can I turn the array into a hash so I can pass a reference to the has to the sub? Like this, perhaps:
    debug($href);

    I suppose that my hash would look like this:
    my $href = {
    username => $username,
    password => password,
    role => $role,
    session => $session,
    date => $date,
    time => $time,
    };

    As I say, this is probably frequently asked, but I may not know how to ask the question. Thanks CC.
     
    ccc31807, Mar 21, 2014
    #1
    1. Advertisements

  2. There's no way to access a 'my' variable 'by name' because at run time,
    its "name" is an index into the lexical pad (term?) it belongs to. This
    means the only way to achieve this is to generate a string containing
    the Perl code creating the anonymous has and executing this code via
    eval in a scope where the desired set of my variables exists. Example:

    -------------
    my $username = 'Joe';
    my $password = 'somepassword';
    my $role = 'user';
    my $session = 'q1w2e3r4t5y6';
    my $date = '2014-03-21';
    my $time = '12345678';

    my @debugarray = qw(username password role session date time);

    sub make_hash_init
    {
    my $code;

    $code = '{';
    $code .= sprintf('%s => $%s,', $_,$_) for @_;
    return $code.'}';
    }

    my $hdebug = eval(make_hash_init(@debugarray));

    printf("%s\t%s\n", $_, $hdebug->{$_}) for keys(%$hdebug);
    -------------
     
    Rainer Weikusat, Mar 21, 2014
    #2
    1. Advertisements

  3. ccc31807

    $Bill Guest

    Obviously this only gets the content of each var at the time the
    hash is created - changing one of them won't change what's in the
    hash:

    use strict;
    use warnings;

    my $username = 'Joe';
    my $password = 'somepassword';
    my $role = 'user';
    my $session = 'q1w2e3r4t5y6';
    my $date = '2014-03-21';
    my $time = '12345678';
    my @debugarray = qw(username password role session date time);

    my $href;
    foreach (@debugarray) { eval "\$href->{$_} = \$$_"; }
    debug ($href);
    exit;

    #- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -

    sub debug {
    my $href = shift;

    print "-------------begin debugging data------------\n";
    foreach my $key (sort keys %{$href}) {
    print "$key = $href->{$key}\n";
    }
    print "-------------end debugging data------------\n";

    }

    __END__
     
    $Bill, Mar 21, 2014
    #3
  4. # here you go

    use strict;
    use warnings;

    my $username = 'Joe';
    my $password = 'somepassword';
    my $role = 'user';
    my $session = 'q1w2e3r4t5y6';
    my $date = '2014-03-21';
    my $time = '12345678';
    my @debugarray = qw( username password role session date time fakevar1
    fakevar2);
    my %hash;



    foreach my $var (@debugarray) {
    $_ = eval "\$$var";
    $hash{$var} = $_ unless $@
    }


    use Data::Dumper; print Dumper \%hash;
     
    George Mpouras, Mar 21, 2014
    #4
  5. See PadWalker for caveats:

    use PadWalker qw/peek_my/;
    use feature 'say';

    my $username = 'Joe';
    ....
    my @debugarray = qw/$username $password $role $session $date $time/;
    debug( peek_my(0), \@debugarray );

    sub debug {
    my ($href, $aref ) = @_;
    foreach my $key (@$aref) {
    say "$key = ", ${$href->{$key}};
    }
    }
     
    Charles DeRykus, Mar 23, 2014
    #5
  6. cool !
     
    George Mpouras, Mar 24, 2014
    #6
  7. Rainer Weikusat, Mar 24, 2014
    #7
  8. Also mentions "PadWalker is particularly useful for debugging. It's
    even used by Perl's built-in debugger..."

    So it may be worth the risk here. YMMV.
     
    Charles DeRykus, Mar 24, 2014
    #8
  9. Being able to replace a tiny bit of 'safe' (in the sense that it works
    only with documented interfaces and doesn't fiddle around with internal
    data structures of the interpreter) with a fairly large bit of (not
    exactly expertly written) C code isn't worth any risks.
     
    Rainer Weikusat, Mar 24, 2014
    #9
  10. That's overreaching IMO. You're deprecating the value of a module
    even used by "Perl's built-in debugger" and especially, in this
    case, since the use was limited to debug. You should throw out Perl's
    built-in debugger then for the same reason. Caution tips over and
    becomes FUD.
     
    Charles DeRykus, Mar 25, 2014
    #10
  11. ccc31807

    Kaz Kylheku Guest

    A lexical environment is not something that is passed down to a child function:
    doing so (as an exposed feature) makes it a de facto dynamic environment.

    Programs that depend on a lexical environment being treated as a dynamic
    environment (via some internal escape hatch) should be written with the
    understanding that the author is wrecking the lexical scope paradigm.

    This falls into the "dumb hack" category when used other than for the intended
    purpose of supporting the debugger as part of the implemenation. If Perl ever
    becomes a properly compiled language, this area will have to drastically
    change, such that programs which depend on it will break.
     
    Kaz Kylheku, Mar 25, 2014
    #11
  12. ccc31807

    Tim McDaniel Guest

    So far as I've seen, that's Rainer's usual approach to modules from
    CPAN, for example, so I'm not surprised to see the same opinion here.

    You write that PadWalker is used in the Perl debugger, but
    perl -e 'use PadWalker'
    fails for me on the systems I have available, so I don't understand
    what's going on with it.
     
    Tim McDaniel, Mar 25, 2014
    #12
  13. And the documentation makes it clear that it's particularly useful for
    debugging...and not recommended for production code. You need enough
    rope to climb into the nooks and crannies of a language even if it's
    dangerous and tomorrow you may need a better rope. The "Perl Hacks"
    segment on PadWalker shows a couple of cases where breaking
    encapsulation is useful and a very apt rationale:

    "It's scary and wrong, but sometimes it's just what you need".
     
    Charles DeRykus, Mar 25, 2014
    #13
  14. I see in perldebug that using the "y" command requires PadWalker to be
    installed.
     
    Charles DeRykus, Mar 25, 2014
    #14
  15. I didn't write that I thought any risk was associated with using this
    module and in fact, I don't think so, except possibly that it may not or
    not anymore or not at all be compatible with some Perl versions, IOW,
    "it may seem like a free download now but you will have to maintain this
    code". Considering that versus

    eval('{'.join(',', map { "$_, \$$_" } @a).'}');

    this becomes a very bad tradeoff.
     
    Rainer Weikusat, Mar 25, 2014
    #15
  16. That's my usual approach to human gateways answering any Perl question
    by (blindly) forwarding something the CPAN search engine returned: It
    shifts the topic of discussion away from the original question towards
    the 'free download du jour'.
    According to the documentation, auto-completion of lexical variable
    names is provided via PadWalker if it is available. It also seems to be
    a core part of the/ an Eclipse Perl debugger.
     
    Rainer Weikusat, Mar 25, 2014
    #16
  17. Hmm ... sorry, but I don't need any more Perl-level access to the
    internal data structures of the interpreter in order to program in Perl/
    for perl than I need userspace access to internal kernel data structures
    for writing UNIX(*) applications.
    The actual example is "dark magic you don't have to understand in order
    to use" (this cries out loud for banging some sense into the guy who
    wrote this --- there's nothing magical about clumsily written C code
    accessing perl data structures and trying to use something one doesn't
    understand is a recipe for disaster more of than not) in order to do
    something which could have been accomplished by inserting a
    print-statement into the example closure or even by running the
    unadorned program via perl debugger and using a watch point.
     
    Rainer Weikusat, Mar 25, 2014
    #17
    1. Advertisements

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 (here). After that, you can post your question and our members will help you out.
Similar Threads
There are no similar threads yet.
Loading...