davorg has asked for the wisdom of the Perl Monks concerning the following question:

Am I missing something obvious here?

#!/usr/bin/perl -w use strict; package Tie::Hash::Test; use Tie::Hash; use vars qw(@ISA); @ISA = 'Tie::StdHash'; sub FETCH { print "wantarray is ", wantarray ? "true\n" : "false\n"; return $_[0]->{$_[1]}; } package main; my %h; tie %h, 'Tie::Hash::Test'; %h = (one => 1, two => 2); my $scalar = $h{one}; my @array = $h{two};

This prints out "wantarray is false" on both accesses. To me, this implies that Perl is doing something strange behind the scenes and is forcing the FETCH call to always be in scalar context, when I'd expect the second call to be evaluated in list context.

Any clues?

--
<http://www.dave.org.uk>

"Perl makes the fun jobs fun
and the boring jobs bearable" - me

Edited 2001-05-24 by Ovid

Replies are listed 'Best First'.
Re: wantarray and Tied Hashes
by Vynce (Friar) on May 24, 2001 at 15:02 UTC

    i seem to recall that hashes, even tied ones, are defined as associating an array of scalar values with an array of lookup keys; as such, i would expect that it's pretty likely that perl always calls FETCH in a scalar context.

    as a quick test, you could try calling FETCH yourself in an array context, by saying (i think)

    my @array_i_said = FETCH(\%h, 'one');
    but, at the moment, i am not at a machine with perl. (shhh! don't tell anyone.) anyway, if that does want an array, then all is in order and perl is calling FETCH in a scalar context regardless; which, as i said, makes sense to me, since we might assume that hash values are scalars.

    i do wonder if there's a reason. is there any situation where FETCH would, if it kept the context the hash lookup was called in, return a list when we really want a scalar? i can't think of one...

    .

      Thanks for the ideas. I tried adding the following lines to my test script:

      $scalar = tied(%h)->FETCH('one'); @array = tied(%h)->FETCH('two');

      And that returned

      wantarray is false wantarray is true

      so it seems to me that Perl is doing something to force scalar context somewhere in the tie interface.

      To explain why I want FETCH to be callable in a list context, look at Tie::Hash::Regex. I'm thinking that if a hash is matching keys using regexes, then you could match more than one key and return a list of values in list context.

      --
      <http://www.dave.org.uk>

      "Perl makes the fun jobs fun
      and the boring jobs bearable" - me

        People would be a bit surprised to find $hash{key} returning a list. I like the fact that not even tied hashes can break this expectation. I don't think you should use $hash{key} as an all-purpose replacement for funct("key"). If you are going to provide your functionality via a "hash-like" interface, then I think you should make it act like a hash; which means that it can only take a single string as input and can only return a single value.

        Next you'll be wanting to tie scalars such that $x returns a list!!

        If you want to return multiple values, then you'll have to return a reference to an array.

        What I did with this was that I allowed the user to specify whether they wanted a list (er, ref to array) for each hash:

        tied(%hash)->WantList("always"); tied(%hash)->WantList("never"); tied(%hash)->WantList("forMultiples");
        (that isn't really a suggested interface, just a quick hack at a way to describe what I'm talking about). So each user could decide whether they wanted to write code like:
        $first= $hash{key}[0]; # or $first= $hash{key}; # or $values= $hash{key}; $first= ref($values) ? $values->[0] : $values;

                - tye (but my friends call me "Tye")
Re (tilly) 1: ttwantarray/tt and Tied Hashes
by tilly (Archbishop) on May 24, 2001 at 18:10 UTC
    It doesn't seem so strange to me.

    What is going on in a tie is this. When you go to use the tied structure, Perl figures out what requests it wants to do, and then calls your module for each request. So you pick up the context in which Perl calls FETCH, which apparently nobody thought to put in the context in which the hash lookup is found.

    But now some people are wondering why there would be any distinction here, isn't the tie translation pretty direct? Well it isn't, and I can give a simple related example. Would most people consider it a bug if hash slices did not work with tied hashes? Yes. Would it be reasonable to have every person writing a tied hash have to reimplement the slice semantics? No. So Perl does that for you...

    Anyways for what you want you will probably have to talk to p5p...