in reply to (FIRST|NEXT)KEY in context

this thread is 6 years old; nevertheless, i can't make each() work on a tied hash :(

it is clear from the perltie documentation that the implementaion of each() is via FIRSTKEY and NEXTKEY. if that is so, then they must return a list in list context.

witness each documentation:

When called in list context, returns a 2-element list consisting of the key and value for the next element of a hash, so that you can iterate over it. When called in scalar context, returns only the key for the next element in the hash.

(emphasis mine)

if the each() documentation is true, then FIRSTKEY/NEXTKEY simply must return a list in list context.

and they do, but only if the return value of each() returned directly.

witness this example code:

use warnings; use strict; $\ = $/ = "\n"; sub ifdef { defined ($_[0]) ? $_[0] : ifdef($_[1], 'undef'); } ################################################## # # return each directly # package TIED_HASH_1; use Tie::Hash; our @ISA = qw(Tie::StdHash); sub FIRSTKEY { print "TIED_HASH_1 FIRSTKEY " . (wantarray ? "array" : "scalar"); my $a = scalar keys %{$_[0]}; return each %{$_[0]}; } sub NEXTKEY { print "TIED_HASH_1 NEXTKEY " . (wantarray ? "array" : "scalar"); return each %{$_[0]}; } ################################################## # # return each INdirectly # package TIED_HASH_2; use Tie::Hash; our @ISA = qw(Tie::StdHash); sub FIRSTKEY { print "TIED_HASH_2 FIRSTKEY " . (wantarray ? "array" : "scalar"); my $a = scalar keys %{$_[0]}; my ($x,$y) = each %{$_[0]}; print "x='$x' y='$y'"; # note $x and $y are fine return ($x, $y); } sub NEXTKEY { print "TIED_HASH_2 NEXTKEY " . (wantarray ? "array" : "scalar"); my ($x,$y) = each %{$_[0]}; print "x='$x' y='$y'"; # note $x and $y are fine return ($x, $y); } ################################################## # package main; my %h_untied; my %h_tied_1; my %h_tied_2; tie %h_tied_1, 'TIED_HASH_1'; tie %h_tied_2, 'TIED_HASH_2'; $h_untied{unt_a}=11; $h_untied{unt_b}=22; $h_tied_1 {t_1_a}=11; $h_tied_1 {t_1_b}=22; $h_tied_2 {t_2_a}=11; $h_tied_2 {t_2_b}=22; my ($k, $v); my @res; print "-------------------- untied hash works fine"; ($k, $v) = each %h_untied; print "k='$k' v='$v'"; ($k, $v) = each %h_untied; print "k='$k' v='$v'"; print "-------------------- tied hash returning each's return directly + works fine"; ($k, $v) = each %h_tied_1; print "k='$k' v='".ifdef($v)."'"; ($k, $v) = each %h_tied_1; print "k='$k' v='".ifdef($v)."'"; print "-------------------- tied hash returning its own list is brok"; ($k, $v) = each %h_tied_2; print "k='$k' v='".ifdef($v)."'"; ($k, $v) = each %h_tied_2; print "k='$k' v='".ifdef($v)."'";

Output:

-------------------- untied hash works fine k='unt_b' v='22' k='unt_a' v='11' -------------------- tied hash returning each's return directly works +fine TIED_HASH_1 FIRSTKEY scalar k='t_1_b' v='22' TIED_HASH_1 NEXTKEY scalar k='t_1_a' v='11' -------------------- tied hash returning its own list is brok TIED_HASH_2 FIRSTKEY scalar x='t_2_b' y='22' k='22' v='undef' TIED_HASH_2 NEXTKEY scalar x='t_2_a' y='11' k='11' v='undef'

you can see that each() called on TIED_HASH_2 simply does not work.

The only explanation i can see for this is that each() uses its own wantarray; some kind of wantarray_special_for_each or something.

but i come to the monks seeking wisdom because maybe there's something else going on here i can't see.

UPDATE: (forgot to include output of this code. 1am postings come with some risks ;) and fixed slight code bug)

Replies are listed 'Best First'.
Re^2: (FIRST|NEXT)KEY in context
by Anonymous Monk on Feb 12, 2010 at 07:25 UTC

      i'm not sure if you were answering my question or trying to ask a question yourself.

      In your case, the reason why you get an infinite loop is that the keys() call resets the iterator that is shared among each(), keys() and values();. so in your loop the iterator gets set to the beginning every iteration by the call to keys()

      but the docs you pointed to explain that. so i presume you knew that. if this is supposed to be an answer to my query, i aplogize but i dont understand. in particular, my issue only comes up when the hash is tied.

      As for moving my query to its own thread, i actually wantd it here, because it appears the OP and i are asking the same question. I figured i'd keep perlmonks organized by keeping the topic all in one place. Are you saying i'll get less attn as a reply rather than an original post?

      Thanks.

        in particular, my issue only comes up when the hash is tied.

        Because you call keys immediately before calling each.