Importing an hash in a lexical scope

Discussion in 'Perl Misc' started by Stefano Sabatini, Mar 13, 2007.

  1. Hi perl guys,

    I would like to import an hash in a lexycal scope, so to be able
    to access the values of the hash as they were lexicals variables
    defined in the current lexycal scope.

    For example I would like to define somewhere an hash like:
    my %hash = (one => 1, two => 2, three => 3, four => 4);

    and then be able to access the variables $one, $two, $three after
    importing them:
    {
    # import the hash
    ...
    print "One is $one, two is $two, three is $three and so on";
    }

    I successfully achieved to import an hash into the current package using
    this incantation:

    foreach (keys %hash) {
    *$_ = \$hash{$_};
    }

    I also tried this:

    {
    my $keys_str;
    foreach (keys %hash) { $keys_str.= "\$$_, " };

    # here it evals the code in the evalled code lexycal environment, which is
    # (unfortunately) not the current lexycal environment, so the
    # lexycal binding is immediately discarded

    eval "my ($keys_str)";

    no strict;
    # this cause the creation of global (package) variables
    # and don't warn 'cause of the no strict pragma
    foreach (keys %hash) {
    eval "\$$_ = $hash{$_};";
    }
    }

    but after some debugging and thinkering I realized it can't work (as
    explained in the comments above).

    So I'm thinking maybe it's not possible at all to achieve my goal, or
    maybe I can't simply see how.

    Any help or suggestion will be highly appreciated.

    Many cheers
    --
    Stefano Sabatini
    Linux user number 337176 (see http://counter.li.org)
    Stefano Sabatini, Mar 13, 2007
    #1
    1. Advertising

  2. Stefano Sabatini

    Uri Guttman Guest

    >>>>> "SS" == Stefano Sabatini <> writes:

    SS> I would like to import an hash in a lexycal scope, so to be able
    SS> to access the values of the hash as they were lexicals variables
    SS> defined in the current lexycal scope.

    SS> For example I would like to define somewhere an hash like:
    SS> my %hash = (one => 1, two => 2, three => 3, four => 4);

    SS> and then be able to access the variables $one, $two, $three after
    SS> importing them:
    SS> {
    SS> # import the hash
    SS> ...
    SS> print "One is $one, two is $two, three is $three and so on";
    SS> }

    that is a very foolish idea in several ways. first, you can't import
    into lexical scope, only into the symbol table. second, the whole point
    of hashes is not to have individual variables for each value when they
    are related. what you are asking for is symbolic (as i said, lexical
    won't even work) references which are a very bad idea.

    SS> I successfully achieved to import an hash into the current package using
    SS> this incantation:

    SS> foreach (keys %hash) {
    SS> *$_ = \$hash{$_};
    SS> }

    was use strict enabled? won't work then.

    SS> I also tried this:

    SS> {
    SS> my $keys_str;
    SS> foreach (keys %hash) { $keys_str.= "\$$_, " };

    SS> # here it evals the code in the evalled code lexycal environment, which is
    SS> # (unfortunately) not the current lexycal environment, so the
    SS> # lexycal binding is immediately discarded

    SS> eval "my ($keys_str)";

    nasty.

    SS> no strict;
    SS> # this cause the creation of global (package) variables
    SS> # and don't warn 'cause of the no strict pragma
    SS> foreach (keys %hash) {
    SS> eval "\$$_ = $hash{$_};";
    SS> }
    SS> }

    again nasty.

    SS> but after some debugging and thinkering I realized it can't work (as
    SS> explained in the comments above).

    why do you think you need to do this? will it make your code much
    cleaner or easier? since you MUST know the names of the hash keys in
    advance since you want to refer to them by name (in whatever scope), why
    would a general import help? all you save would be typing the name of
    the hash.

    SS> So I'm thinking maybe it's not possible at all to achieve my goal, or
    SS> maybe I can't simply see how.

    you can't in a lexical scope. it is dumb in the symbol table.

    SS> Any help or suggestion will be highly appreciated.

    don't do it at all. use the hash as it is. you won't gain much at all
    doing what you want. you may think you do but there are other
    ways. since you MUST know the names you will be using, why not just do
    this:

    my $first = $hash{first} ;

    and so on. do that in the tightest scope just before where you use
    $first. and if you only use $first one time then don't even do that,
    just use the hash.

    uri

    --
    Uri Guttman ------ -------- http://www.stemsystems.com
    --Perl Consulting, Stem Development, Systems Architecture, Design and Coding-
    Search or Offer Perl Jobs ---------------------------- http://jobs.perl.org
    Uri Guttman, Mar 13, 2007
    #2
    1. Advertising

  3. Hi Guri, and thanks for your reply.

    On 2007-03-13, Uri Guttman <> wrote:
    >>>>>> "SS" == Stefano Sabatini <> writes:

    >
    > SS> For example I would like to define somewhere an hash like:
    > SS> my %hash = (one => 1, two => 2, three => 3, four => 4);
    >
    > SS> and then be able to access the variables $one, $two, $three after
    > SS> importing them:
    > SS> {
    > SS> # import the hash
    > SS> ...
    > SS> print "One is $one, two is $two, three is $three and so on";
    > SS> }
    >
    > that is a very foolish idea in several ways. first, you can't import
    > into lexical scope, only into the symbol table. second, the whole point
    > of hashes is not to have individual variables for each value when they
    > are related. what you are asking for is symbolic (as i said, lexical
    > won't even work) references which are a very bad idea.
    >
    > SS> I successfully achieved to import an hash into the current package using
    > SS> this incantation:
    >
    > SS> foreach (keys %hash) {
    > SS> *$_ = \$hash{$_};
    > SS> }
    >
    > was use strict enabled? won't work then.


    well, I was using no strict there.
    is there a better way to import an hash in the main package (without
    disabling the strict pragma), or is this a bad practice to avoid?

    >
    > SS> I also tried this:
    >
    > SS> {
    > SS> my $keys_str;
    > SS> foreach (keys %hash) { $keys_str.= "\$$_, " };
    >
    > SS> # here it evals the code in the evalled code lexycal environment, which is
    > SS> # (unfortunately) not the current lexycal environment, so the
    > SS> # lexycal binding is immediately discarded
    >
    > SS> eval "my ($keys_str)";
    >
    > nasty.
    >
    > SS> no strict;
    > SS> # this cause the creation of global (package) variables
    > SS> # and don't warn 'cause of the no strict pragma
    > SS> foreach (keys %hash) {
    > SS> eval "\$$_ = $hash{$_};";
    > SS> }
    > SS> }
    >
    > again nasty.


    well, I agree, and indeed it was just an experiment, and I'd think twice
    before to put it in production code.

    > SS> but after some debugging and thinkering I realized it can't work (as
    > SS> explained in the comments above).
    >
    > why do you think you need to do this? will it make your code much
    > cleaner or easier? since you MUST know the names of the hash keys in
    > advance since you want to refer to them by name (in whatever scope), why
    > would a general import help? all you save would be typing the name of
    > the hash.


    I have this problem. There is portion of user defined code (via a
    code reference) loaded at run-time, and an hash containing options values
    used in that code, which again is defined by the user at run-time.

    I would like the user to use all the variables defined in the hash as
    they were defined as regular variables in the code environment, rather
    than hash entries.

    For example:

    my %options= (name => "John Doe",
    programming_language_used => "Perl",
    vice => "nastiness");


    then I would like to access these values in the code in this way:

    my $funref = {
    print "My name is $name, I'm programming in $programming_language_used, ",
    "my vice is $vice";
    }

    rather than like this:
    my $funref = {
    # $options is a reference to the options hash
    my ($options) = @_;
    print "My name is $options->{name}, ",
    "I'm programming in $options->{programming_language_used}, ",
    "my vice is $options->{vice}";
    }

    but, basing on what you said, I see it would be better (easier on the
    programmer, *safer*) the latter, even if it is sligthly more prolisse.

    > SS> So I'm thinking maybe it's not possible at all to achieve my goal, or
    > SS> maybe I can't simply see how.
    >
    > you can't in a lexical scope. it is dumb in the symbol table.
    >
    > SS> Any help or suggestion will be highly appreciated.
    >
    > don't do it at all. use the hash as it is. you won't gain much at all
    > doing what you want. you may think you do but there are other
    > ways. since you MUST know the names you will be using, why not just do
    > this:
    >
    > my $first = $hash{first} ;
    >
    > and so on. do that in the tightest scope just before where you use
    > $first. and if you only use $first one time then don't even do that,
    > just use the hash.


    OK, and many thanks for your knowledgable help.

    as I said I was experimenting, but it seems that the solution I was
    contriving wasn't a good one.

    Cheers
    --
    Stefano Sabatini
    Linux user number 337176 (see http://counter.li.org)
    Stefano Sabatini, Mar 14, 2007
    #3
  4. Stefano Sabatini

    Uri Guttman Guest

    >>>>> "SS" == Stefano Sabatini <> writes:

    >> was use strict enabled? won't work then.


    SS> well, I was using no strict there.

    that is the whole problem. strict is meant to stop you from doing evil
    things.

    SS> is there a better way to import an hash in the main package (without
    SS> disabling the strict pragma), or is this a bad practice to avoid?

    you haven't explained your bigger picture. why do you need to import the
    hash? can you pass it as an argument by reference? can you remotely
    access it via a sub or method? there are other ways to share data than
    just importing. you seem to be stuck on only import and i see no reason
    from you why that is so critical.

    >>

    SS> I also tried this:
    >>

    SS> {
    SS> my $keys_str;
    >> again nasty.


    SS> well, I agree, and indeed it was just an experiment, and I'd think twice
    SS> before to put it in production code.

    good! you learned something! :)

    >> why do you think you need to do this? will it make your code much
    >> cleaner or easier? since you MUST know the names of the hash keys in
    >> advance since you want to refer to them by name (in whatever scope), why
    >> would a general import help? all you save would be typing the name of
    >> the hash.


    SS> I have this problem. There is portion of user defined code (via a
    SS> code reference) loaded at run-time, and an hash containing options values
    SS> used in that code, which again is defined by the user at run-time.

    SS> I would like the user to use all the variables defined in the hash as
    SS> they were defined as regular variables in the code environment, rather
    SS> than hash entries.

    that is bas as i have already explained. if they know the names of the
    hash elements (not variables) they can use those directly. having them
    automatically assigned to lexicals is not a win. let them do it in code
    as i have shown you if they want that.

    SS> print "My name is $name, I'm programming in
    SS> $programming_language_used, ", "my vice is $vice";


    SS> rather than like this:
    SS> my $funref = {
    SS> # $options is a reference to the options hash
    SS> my ($options) = @_;
    SS> print "My name is $options->{name}, ",
    SS> "I'm programming in $options->{programming_language_used}, ",
    SS> "my vice is $options->{vice}";
    SS> }

    so what is so bad about that? use a shorter name for $options if you
    want. or use a templater (see Template::Simple on cpan for something
    that will do that quickly and easily)

    untested:

    use Template::Simple ;

    my $tmpl = Template::Simple->new() ;

    my $in = <<INPUT ;
    My name is [%name%],
    I'm programming in [%programming_language_used%],
    my vice is [%vice%]
    INPUT

    # put into $options the hash info as above (no code here for that)

    print $tmpl->render( $options, $input ) ;

    clean, fast, safe, no extra $options all around. $tmpl is reusable too.

    SS> but, basing on what you said, I see it would be better (easier on the
    SS> programmer, *safer*) the latter, even if it is sligthly more prolisse.

    SS> So I'm thinking maybe it's not possible at all to achieve my goal, or
    SS> maybe I can't simply see how.

    your goal isn't worthy of being achieved as it is misguided. putting
    lexicals into a remote scope would be dangerous even it could be
    done. what if outside data set some other lexical that was used for some
    external operation? a security hole a mile wide. php is famous for this
    sort of thing (all cgi params automatically become variables, same nasty
    concept).

    as i have shown you here, you can use a templater. or have the users
    assign their own lexicals. and there is nothing wrong with your basic
    hash access as you know that works. why do you think your users need
    such a minor extra little helper like your lexical idea? the other
    solutions are almost as short and so much better in many ways.

    uri

    --
    Uri Guttman ------ -------- http://www.stemsystems.com
    --Perl Consulting, Stem Development, Systems Architecture, Design and Coding-
    Search or Offer Perl Jobs ---------------------------- http://jobs.perl.org
    Uri Guttman, Mar 14, 2007
    #4
  5. On 2007-03-14, Uri Guttman <> wrote:
    >>>>>> "SS" == Stefano Sabatini <> writes:

    >
    > >> was use strict enabled? won't work then.

    >
    > SS> well, I was using no strict there.
    >
    > that is the whole problem. strict is meant to stop you from doing evil
    > things.
    >
    > SS> is there a better way to import an hash in the main package (without
    > SS> disabling the strict pragma), or is this a bad practice to avoid?
    >
    > you haven't explained your bigger picture. why do you need to import the
    > hash? can you pass it as an argument by reference? can you remotely
    > access it via a sub or method? there are other ways to share data than
    > just importing. you seem to be stuck on only import and i see no reason
    > from you why that is so critical.


    There is no particular reason for wondering about to import an hash. I
    only stepped on the problem, I considerd the basic hash access method
    and I wondered if it was possible to use that other method, that
    seemed to slightly simplify the user code. Maybe I should have asked
    myself if that was a good thing to do, and as you say maybe it's not
    (for the same reasons you explained).

    But I thought that was an interesting problem, I meant good to stretch
    my own knowledge and awareness of the language.

    And if you look at the problem from another point of view maybe my
    question doesn't appear so much dumb: it's possible to import some
    symbols from a package (that is an hash) into the current package,
    it's possible (although disabling strict) to import a regular hash in
    the current package as I showed, so maybe it could be possible to
    import an hash in a lexycal environment.

    > your goal isn't worthy of being achieved as it is misguided. putting
    > lexicals into a remote scope would be dangerous even it could be
    > done. what if outside data set some other lexical that was used for some
    > external operation? a security hole a mile wide. php is famous for this
    > sort of thing (all cgi params automatically become variables, same nasty
    > concept).
    > as i have shown you here, you can use a templater. or have the users
    > assign their own lexicals. and there is nothing wrong with your basic
    > hash access as you know that works. why do you think your users need
    > such a minor extra little helper like your lexical idea? the other
    > solutions are almost as short and so much better in many ways.
    >


    OK, indeed it's doesn't seems that bad, and I think I'll stick with
    the basic hash access.

    Many thanks.

    Cheers
    --
    Stefano Sabatini
    Linux user number 337176 (see http://counter.li.org)
    Stefano Sabatini, Mar 15, 2007
    #5
  6. Stefano Sabatini

    Mumia W. Guest

    On 03/15/2007 09:49 AM, Stefano Sabatini wrote:
    > On 2007-03-14, Uri Guttman <> wrote:
    >>
    >> you haven't explained your bigger picture. why do you need to import the
    >> hash? [...]

    >
    > There is no particular reason for wondering about to import an hash. I
    > only stepped on the problem, I considerd the basic hash access method
    > and I wondered if it was possible to use that other method, that
    > seemed to slightly simplify the user code. Maybe I should have asked
    > myself if that was a good thing to do, and as you say maybe it's not
    > (for the same reasons you explained).
    >
    > But I thought that was an interesting problem, I meant good to stretch
    > my own knowledge and awareness of the language.
    > [...]


    I probably have no business posting this since the thread is basically
    over, but I just got so curious that I had to see if it was possible,
    and it is:

    #!/usr/bin/perl
    use strict;
    use warnings;
    use English qw(-no_match_vars);

    my %h = (USER => 'han',
    EMAIL => '',
    PASSWORD => 'passWord');

    $RS='';
    while (my $custcode = <DATA>) {
    my $code = join "",
    map "my \$$_ = q{$h{$_}};\n", keys %h;
    $code .= "\n$custcode\n";
    # print $code;
    eval $code;
    if ($@) { die $@; }
    }

    __DATA__
    local ($, , $\ ) = (' , ', "\n");
    print "User Info:", $USER, $EMAIL, $PASSWORD;

    print "My customer's email address is $EMAIL.\n";

    use Digest::MD5 qw(md5_hex);
    local $\ = "\n";
    print "User ${USER}'s md5 password = ", md5_hex($PASSWORD);

    __END__

    In this program, each segment of customer code is separated by a blank
    line, and there are three segments, so the while loop executes three
    times. If you don't have Digest::MD5 installed, you get to see what
    happens when "customer code" fails :)

    However, as Uri said, using a hash is best. The difference between
    ${USER} and $h{USER} is nominal.
    Mumia W., Mar 16, 2007
    #6
    1. Advertising

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

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. Matt Knepley

    Lexical Scope

    Matt Knepley, Oct 30, 2003, in forum: Python
    Replies:
    3
    Views:
    412
    Paul Clinch
    Oct 30, 2003
  2. Replies:
    18
    Views:
    486
    Bengt Richter
    Dec 17, 2005
  3. globalrev

    python: lexical or dynamic scope?

    globalrev, May 13, 2008, in forum: Python
    Replies:
    3
    Views:
    868
    Mark Wooding
    May 14, 2008
  4. Xah Lee
    Replies:
    0
    Views:
    2,221
    Xah Lee
    Feb 26, 2009
  5. rp
    Replies:
    1
    Views:
    490
    red floyd
    Nov 10, 2011
Loading...

Share This Page