in reply to Question about the symbol table

This code was obviously written without strict and should therefore only serve as an example as to why strict should always be used. Anyways, on to the analysis:

The code is obviously supposed to sort its output by number of logins, but if you run it several times, you'll see it doesn't work!

First clue as to the error: If you turn on warnings and strict - as one always should, even when trying to understand legacy code! - and then declare our ($hash, %hash); at the top of the code, you'll see warnings like this: "Use of uninitialized value in numeric comparison (<=>) at ..."

sub KeysByLogins is the only place where %hash is referenced, and there it is only read from, not written to, that's why it remains empty.

If you break the Schwartzian Transform happening in that sub into pieces, you can see that happening:

sub KeysByLogins { my $hash = shift; my @temp = map { [ $hash{$_}->{logins}, $_ ] } keys %$hash; print Dumper(\@temp); return map { $_->[1] } sort { $a->[0] <=> $b->[0] } @temp; }

The first element in each pair is always undef, because %hash is empty.

So it's really not got much to do with the symbol table, just a single typo bug caused by not using strict.

Replies are listed 'Best First'.
Re^2: Question about the symbol table
by Anonymous Monk on Feb 26, 2016 at 16:25 UTC

    P.S. To directly answer your question (and make a minor correction*)

    Would that be because %hash only springs up in the scope of the subroutine,

    No, undeclared variables (when strict vars is not in use) are package variables (global), see e.g. our. In this case, there are two, the scalar $hash which holds a reference to an anonymous hash (the data structure being used in this code), and %hash, a hash which is only read from in one place in the code, which is why it remains almost empty*.

    * The dereference operation actually autovivifies some empty anonymous hashes:

    print Dumper(\%hash); __END__ $VAR1 = { 'user2' => {}, 'user3' => {}, 'user1' => {} };