![]() |
Importing an hash in a lexical scope
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) |
Re: Importing an hash in a lexical scope
>>>>> "SS" == Stefano Sabatini <stefano.sabatini-lala@poste.it> 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 ------ uri@stemsystems.com -------- http://www.stemsystems.com --Perl Consulting, Stem Development, Systems Architecture, Design and Coding- Search or Offer Perl Jobs ---------------------------- http://jobs.perl.org |
Re: Importing an hash in a lexical scope
Hi Guri, and thanks for your reply.
On 2007-03-13, Uri Guttman <uri@stemsystems.com> wrote: >>>>>> "SS" == Stefano Sabatini <stefano.sabatini-lala@poste.it> 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) |
Re: Importing an hash in a lexical scope
>>>>> "SS" == Stefano Sabatini <stefano.sabatini-lala@poste.it> 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 ------ uri@stemsystems.com -------- http://www.stemsystems.com --Perl Consulting, Stem Development, Systems Architecture, Design and Coding- Search or Offer Perl Jobs ---------------------------- http://jobs.perl.org |
Re: Importing an hash in a lexical scope
On 2007-03-14, Uri Guttman <uri@stemsystems.com> wrote:
>>>>>> "SS" == Stefano Sabatini <stefano.sabatini-lala@poste.it> 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) |
Re: Importing an hash in a lexical scope
On 03/15/2007 09:49 AM, Stefano Sabatini wrote:
> On 2007-03-14, Uri Guttman <uri@stemsystems.com> 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 => 'han76@example.com', 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. |
| All times are GMT. The time now is 05:48 PM. |
Powered by vBulletin®. Copyright ©2000 - 2013, vBulletin Solutions, Inc.
SEO by vBSEO ©2010, Crawlability, Inc.