1

I am having difficulties understanding how the referencing and dereferencing of hashes works in perl.

I have a hash of 3 levels defined as this:

%languages = ( 
               'en', ( 
                       'it', ( 'pattern1', '...', 'pattern2', '...' )
                       'de', ( 'pattern1', '...', 'pattern2', '...' )
                     ) 
               'it', ( 
                       'en', ( 'pattern1', '...', 'pattern2', '...' )
                       'de', ( 'pattern1', '...', 'pattern2', '...' )
                     )
               'de', ( 
                       'en', ( 'pattern1', '...', 'pattern2', '...' )
                       'it', ( 'pattern1', '...', 'pattern2', '...' )
                     )
             );

and want to iterate on the second level of one of the hashes of the first level like this:

my $current_language = 'de';
while ( ( my $language, my $patterns ) = each %{ $languages{ $current_language } } )
{
  print $patterns->{'pattern1'};
}

but i get the following error

Can't use string ("en") as a HASH ref while "strict refs" in use

I would appreciate any help on this.

nucka
  • 559
  • 5
  • 12
  • 10
    That assignment is not what you had in your original code, because then your question would be "Why do I get syntax error". It is a really, really bad idea to post approximate code like this. Post the code you have, or a `Data::Dumper` printout of the data structure. – TLP Aug 30 '13 at 16:14
  • Thank you for your feedback I will keep that in mind for my next questions. – nucka Sep 24 '13 at 11:55

2 Answers2

11

In Perl, parens only sort out precedence. The following two lines are equivalent:

(1, 2, 3)
(1, (2, (3)))

Therefore, you are actually assigning

( 
  en       => 'it',
  pattern1 => '...',
  pattern2 => '...' ,
  de       => 'pattern1'
  '...'    => 'pattern2'
  '...'    =>'it',
  en       => 'pattern1',
  ... # I think you got it …
);

You can't actually have nested hashes, but references to nested hashes. You can use { foo => 2} for a hashref literal, and [1, 2, 3] for arrayref literals:

%languages = ( 
           en => { 
                   it => ['pattern1', 'pattern2'],
                   de => ['pattern1', 'pattern2'],
                 },
           ...,
         );

while (my($lang, $patterns) = each $languages{de}) {
  print "$lang has [@$patterns]\n";
}

NOTE: The => (aka "fat comma" operator) is the same operator as the comma, but can be used to emphasize a key-value relationship (and it conveniently automatically add quotes to unquoted strings (barewords) on the left hand side - i.e. hash keys).

Community
  • 1
  • 1
amon
  • 57,091
  • 2
  • 89
  • 149
  • 2
    `=>` also autoquotes its LHS parameter. – TLP Aug 30 '13 at 16:15
  • 3
    @TLP - "autoquotes its LHS parameter" is not exactly the way I would phrase the thought when communicating to a total newbie :) – DVK Aug 30 '13 at 16:27
  • @DVK: Indeed. And nor is *" autoquotes barewords on the LHS"*. – Borodin Aug 30 '13 at 16:48
  • @DVK You guys should not underestimate people. Nor should you try and fight the natural selection. Also, I was not communicating to a total newbie. – TLP Aug 30 '13 at 17:04
  • @TLP - OP of the question is. And natural selection is for languages that aren't dying because every organization using them is switching to Python "because that's what new college graduates know" like mine is. – DVK Aug 30 '13 at 18:36
  • I was not adressing the OP. And I was not referring to languages when I said natural selection. – TLP Aug 30 '13 at 18:53
  • @TLP: It is surely appropriate to write comments in a style that the OP can be expected to comfortable with? – Borodin Sep 02 '13 at 16:25
  • @Borodin I've no idea what you are on about. The comment was directed at amon, so he could improve his answer. It does not matter if the OP could understand it or not. And the comment is not THAT cryptic, its basically plain English except for the acronym LHS. – TLP Sep 02 '13 at 16:37
  • @TLP: There is no reason for your reaction. I framed my comment as a question, hoping for a constructive response. What I said was clear, and I believe you have every *"idea what [I was] on about"*. I think that it is rude to say *anything* that the person who posed the question can't be expected to understand. I assume you wouldn't do it in real life, and the principle applies here too. I wouldn't have said anything except that you excused your phraseology by saying *"I was not addressing the OP"*. There may be several valid reasons why you wrote the way you did, but that isn't one of them. – Borodin Sep 02 '13 at 17:06
  • @Borodin What reaction is that? Maybe you are reading things into my comments that are not there. No, I have no idea why you 3 people think that comment is so hard to understand, nor do I know why you think it is such a big deal even if it was. And you are wrong. Your contention is that I did something wrong by addressing the OP in a too complicated language. I however did not address the OP, which directly disqualifies your argument. Your argument is now "Well, you should have thought of the fact that the OP -- who is a newbie -- might have read your comment and been confused." – TLP Sep 02 '13 at 18:24
  • @Borodin And to that I say, that is too bad, if he has a question he is more than welcome to ask me for a clarification. But the fact of the matter is, I was addressing amon, and no one else. The intent of the comment was to encourage amon to improve his answer, so that the OP learned more about the `=>` operator. – TLP Sep 02 '13 at 18:25
  • Dear Borodin & TLP – On the one hand, your dispute has a comedic value. On the other, it adds nothing to the question (nor, except for the first two comments, to my answer). If this is a meta-discussion on how to write comments then a question on meta.SO might be the place to continue this. If the topic is how we should communicate with non-hardcore Perlers, then blogs.perl.org or a similar venue awaits your opinions. If this is just ranting, go meet on IRC or whatever. But please end this bitching *here*. – amon Sep 02 '13 at 19:03
5

Hash values in Perl must be scalars, and it looks like you are trying to assign lists (or list representing hashes) as hash values. Fortunately, hash references are scalars. I think what you meant to write is:

%languages = ( 

           'en', {
                   'it', { 'pattern1', '...', 'pattern2', '...' },
                   'de', { 'pattern1', '...', 'pattern2', '...' }
                 }, 
           'it', { 
                   'en', { 'pattern1', '...', 'pattern2', '...' },
                   'de', { 'pattern1', '...', 'pattern2', '...' }
                 },
           'de', { 
                   'en', { 'pattern1', '...', 'pattern2', '...' },
                   'it', { 'pattern1', '...', 'pattern2', '...' }
                 }
         );
mob
  • 117,087
  • 18
  • 149
  • 283