Beefy Boxes and Bandwidth Generously Provided by pair Networks
Problems? Is your data what you think it is?

syntax for hashes with variable in name

by equick (Acolyte)
on Nov 22, 2010 at 12:05 UTC ( #872955=perlquestion: print w/replies, xml ) Need Help??
equick has asked for the wisdom of the Perl Monks concerning the following question:


I have a problem with creating a hash which has a a variable in its name. This works ok for arrays ,eg

but not hashes
Here's my script:
#!/usr/bin/perl sub buildconfig; buildconfig; foreach $key(keys %sites){ print "$key\n"; } sub buildconfig{ my ($site, $platform, $webserver, $option); my %sites = map {$_=>1} @sites; # create following variables # %sites = BFH, LPR, UAT, TEST # @all_platforms and %all_platforms = TEST_MLS, TEST_RST, UAT_ +MLS, UAT_RST ... # %platform_TEST = TEST_MLS, TEST_RST, TEST_OPP, TEST_BO ... # @all_webservers and %all_webservers = mls001.test, mls002.te +st, tomcat001.test, tomcat002.test ... # %webservers_TEST_MLS = mls001.test, mls002.test # %deploy_as = prod, standby, demo # %deploy_as_platforms = Prod1, Prod2, UAT, TEST my %sites = map {$_=>1} @sites; foreach $site (@sites) { my %all_platforms = map {$_=>1} @{"platforms_$site"}; my %{"platforms_$site"} = map {$_=>1} @{"platforms_$si +te"}; foreach $platform (keys %{platforms_$site}) { my %all_webservers = map {$_=>1} @{"webservers +_$platform"}; my %{"webservers_$platform"} = map {$_=>1} @{" +webservers_$platform"}; } } my @all_platforms=sort keys(%all_platforms); my @all_webservers=sort keys(%all_webservers); my %deploy_as = map {$_=>1} @deploy_as; my %deploy_as_platforms = map {$_=>1} @deploy_as_platforms; }
but when it's run I get:
Can't declare hash dereference in my at ./ line 30, near "} =" Execution of ./ aborted due to compilation errors.

Could anyone tell me how to fix that please?

Thanks, Ed.

Replies are listed 'Best First'.
Re: syntax for hashes with variable in name
by jethro (Monsignor) on Nov 22, 2010 at 12:47 UTC

    Your immediate problem is that perl interprets your %{ as a hash slice (see for a small example)

    Your larger problem is that you want to use a technique that is a relict from perl4 days and only (if at all) suitable for quick hacks

    Instead of using

    my %{"platform_$site"}; ${"platform_$site"}{"thingy"}= 5; foreach my $x ( keys %{"platform_$site"}) { ...
    use multidimensional hashes
    my %platform; $platform{$site}{"thingy"}= 5; foreach my $x ( keys %{$platform{$site}}) { ...

    You can use the same technique for your arrays as well, i.e. use a so called HashOfArrays:

    push @{$platform{$site}}, 1,2; $platform{$site}[5]= 5; foreach my $x ( @{$platform{$site}}) { ..

    PS: I also notice you don't use 'use warnings;' and 'use strict;' at the beginning of your script. It is highly advisable to include those two lines. Avoids many bug finding sessions later.

      Hash (and array) slices always start with @. No slices start with %.

      my %{"$name"};

      is the same as

      my %{$name}

      which is the same as

      my %$name; # Symbolic dereference

      which no more works than

      my %$ref; # Generic deference

      Your immediate problem is that perl interprets your %{ as a hash slice

      Is this for real?

        is it?

        Let's rule out the fact that this deals with symbolic references, strict tells us ...

        use strict; use warnings; { no strict "refs"; my $site = "foo"; my @{"platforms_$site"} = qw( foo bar ); my %{"platforms_$site"} = map { $_ => 1 } @{"platforms_$site"}; } => Can't declare array dereference in "my" at line 8, near "} =" Execution of aborted due to compilation errors.

        The difference is in the assignment part. You cannot use my there. When you drop those, you get:

        use strict; use warnings; { no strict "refs"; my $site = "foo"; @{"platforms_$site"} = qw( foo bar ); %{"platforms_$site"} = map { $_ => 1 } @{"platforms_$site"}; }

        Which is still bad coding style, but this works.

        Enjoy, Have FUN! H.Merijn

        It was the best explanation I could find at the moment. But I didn't check with deparse or something.

      Thanks for your reply.

      Yes usually I include strict, but I had just taken an extract of an old script I'm patching to work on that particular function.

      I also agree multidimensional arrays are probably the way to go, but if possible I'd rather keep the current variables as they are used throughout the other script.

Re: syntax for hashes with variable in name
by Tux (Abbot) on Nov 22, 2010 at 15:39 UTC

    Don't go that road. Please. Done that, been there. It leads to unwanted things, in the widest sense of "unwanted". Really!

    Symbolic reference (where the name of the hash/array/scalar is in a variable name) can always be made strict and safer by embedding it inside a hash:

    my $hash_name = "platform_$site"; %$hash_name = ( key => $value ); : my $value = ${$hash_name}{key};


    my %global_hash; my $hash_name = "platform_$site"; $global_hash{$hash_name} = { key => $value }; : my $value = $global_hash{$hash_name}{key};

    Or - even better - go with jethro's suggestion to use multidimensional data structures.

    Enjoy, Have FUN! H.Merijn
      ...ditto...but once you've touched some code, you own it, and anything it may or may not do with good or bad data as input. so as much as this sounds as a bit of a pain, you're much better of re-writing the code to use good/clean programming patterns. code with symbolic reference variables is harder to debug/maintain/improve. i once wrote a data reporting perl script initially (and naively) using symbolic reference variables. i immediately re-wrote it using multilevel hashes, and the spaghetti code turned magically into nicely ordered simple subroutines and loops, and halved the number of lines of code.
      the hardest line to type correctly is: stty erase ^H

Log In?

What's my password?
Create A New User
Node Status?
node history
Node Type: perlquestion [id://872955]
Approved by McDarren
and all is quiet...

How do I use this? | Other CB clients
Other Users?
Others exploiting the Monastery: (4)
As of 2018-06-24 21:02 GMT
Find Nodes?
    Voting Booth?
    Should cpanminus be part of the standard Perl release?

    Results (126 votes). Check out past polls.