Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

The future of tied hashes in scalar context

1 view
Skip to first unread message

Rafael Garcia-Suarez

unread,
Dec 2, 2003, 8:23:35 PM12/2/03
to perl5-...@perl.org
With bleadperl :

$ ./perl -Ilib -MTie::SubstrHash -e 'tie%h,"Tie::SubstrHash";$x=%h'
Can't provide tied hash usage; use keys(%hash) to test if empty at -e line 1.

This fatal error was added because
1/ using a tied hash in scalar context returns unreliable result
2/ using keys() behind the scenes to provide a value resets the iterator,
an unwanted side-effect
3/ this was meant as a temporary band-aid for 5.8.1 but was withdrawn
due to backward compatibility problems

Shouldn't we find a better solution, other than completely forbidding
tied hashes in scalar context ? for example, returning 0 or '1/1',
depending on whether the hash is empty or not.

For reference, see :

http://rt.perl.org/rt3/Ticket/Display.html?id=17718
http://www.xray.mpe.mpg.de/mailing-lists/perl5-porters/2003-07/msg01002.html

Tassilo Von Parseval

unread,
Dec 3, 2003, 3:47:48 AM12/3/03
to Rafael Garcia-Suarez, perl5-...@perl.org
On Wed, Dec 03, 2003 at 02:23:35AM +0100 Rafael Garcia-Suarez wrote:

> With bleadperl :
>
> $ ./perl -Ilib -MTie::SubstrHash -e 'tie%h,"Tie::SubstrHash";$x=%h'
> Can't provide tied hash usage; use keys(%hash) to test if empty at -e line 1.
>
> This fatal error was added because
> 1/ using a tied hash in scalar context returns unreliable result
> 2/ using keys() behind the scenes to provide a value resets the iterator,
> an unwanted side-effect
> 3/ this was meant as a temporary band-aid for 5.8.1 but was withdrawn
> due to backward compatibility problems
>
> Shouldn't we find a better solution, other than completely forbidding
> tied hashes in scalar context ? for example, returning 0 or '1/1',
> depending on whether the hash is empty or not.

The most correct (TM) way would probably be to have a SCALAR method in
the class implementing the tie. That doesn't mean it's terribly useful
because in my impression hashes are very seldom used in scalar context
and therefore hardly worth the pain to implement it (not sure how hard
it would be).

Returning some sort of dummy string, such as '-1/-1', will probably do
just as well especially since using a hash in scalar context doesn't
reset the iterator or has other side effects.

Tassilo
--
$_=q#",}])!JAPH!qq(tsuJ[{@"tnirp}3..0}_$;//::niam/s~=)]3[))_$-3(rellac(=_$({
pam{rekcahbus})(rekcah{lrePbus})(lreP{rehtonabus})!JAPH!qq(rehtona{tsuJbus#;
$_=reverse,s+(?<=sub).+q#q!'"qq.\t$&."'!#+sexisexiixesixeseg;y~\n~~dddd;eval

Michael G Schwern

unread,
Dec 3, 2003, 4:12:01 AM12/3/03
to Rafael Garcia-Suarez, perl5-...@perl.org
On Wed, Dec 03, 2003 at 09:47:48AM +0100, Tassilo von Parseval wrote:
> The most correct (TM) way would probably be to have a SCALAR method in
> the class implementing the tie. That doesn't mean it's terribly useful
> because in my impression hashes are very seldom used in scalar context
> and therefore hardly worth the pain to implement it (not sure how hard
> it would be).

%hash = ( foo => 42 ) unless %hash;

Very common to check if a hash is empty by using it in scalar context
rather than using keys(). Most people just care that a hash with keys
returns a true value and a hash without returns false.


--
Michael G Schwern sch...@pobox.com http://www.pobox.com/~schwern/
Let me check my notes.
http://www.sluggy.com

Tassilo Von Parseval

unread,
Dec 3, 2003, 4:58:46 AM12/3/03
to Michael G Schwern, Rafael Garcia-Suarez, perl5-...@perl.org
On Wed, Dec 03, 2003 at 01:12:01AM -0800 Michael G Schwern wrote:

> On Wed, Dec 03, 2003 at 09:47:48AM +0100, Tassilo von Parseval wrote:
> > The most correct (TM) way would probably be to have a SCALAR method in
> > the class implementing the tie. That doesn't mean it's terribly useful
> > because in my impression hashes are very seldom used in scalar context
> > and therefore hardly worth the pain to implement it (not sure how hard
> > it would be).
>
> %hash = ( foo => 42 ) unless %hash;
>
> Very common to check if a hash is empty by using it in scalar context
> rather than using keys(). Most people just care that a hash with keys
> returns a true value and a hash without returns false.

Oh, didn't even know that works. I expected to get '0/8' when an empty
hash is evaluated in scalar context but it returns 0 apparently.

Well, wouldn't that mean that there should be a mechanism for the
programmer to control the behaviour of a tied hash in scalar context,
like having the proposed SCALAR method? Otherwise a tied hash could
never be used like an ordinary one which is wrong IMO since tying is
something that happens behind the scenes. Ideally, a user shouldn't have
to care whether a hash is tied or not.

Rafael Garcia-Suarez

unread,
Dec 3, 2003, 5:20:12 AM12/3/03
to tassilo....@post.rwth-aachen.de, sch...@pobox.com, perl5-...@perl.org
Tassilo von Parseval wrote:
>
> Well, wouldn't that mean that there should be a mechanism for the
> programmer to control the behaviour of a tied hash in scalar context,
> like having the proposed SCALAR method?

I think that's a sensible idea. And add a default SCALAR method
to Tie::Hash or Tie::StdHash. And croak only for tied hashes used
in scalar context and that don't provide a SCALAR method.

> Otherwise a tied hash could
> never be used like an ordinary one which is wrong IMO since tying is
> something that happens behind the scenes. Ideally, a user shouldn't have
> to care whether a hash is tied or not.

Old meme... This is Perl 5 ; when magic is involved behind the
scenes, you´ll never know whether your program is in danger of being
blown away in a sudden burst of octarine.

Elizabeth Mattijsen

unread,
Dec 3, 2003, 6:29:49 AM12/3/03
to tassilo....@post.rwth-aachen.de, Michael G Schwern, Rafael Garcia-Suarez, perl5-...@perl.org
At 10:58 +0100 12/3/03, Tassilo von Parseval wrote:
>Oh, didn't even know that works. I expected to get '0/8' when an empty
>hash is evaluated in scalar context but it returns 0 apparently.

Well, technically no (I think). If you use a string such as that in
a numerical context, Perl takes whatever numbers are at the beginning
of the string and uses that as the value:

$ perl -e 'print 0+"0/8"'
0
$ perl -e 'print 0+"1/8"'
1


Or am I mistaken here?


Liz

Tassilo Von Parseval

unread,
Dec 3, 2003, 6:49:07 AM12/3/03
to Elizabeth Mattijsen, Michael G Schwern, Rafael Garcia-Suarez, perl5-...@perl.org

Perl really returns a plain 0 here:

ethan@ethan:~$ perl -MDevel::Peek -e 'Dump(scalar(%hash))'
SV = IV(0x812b2b8) at 0x811e408
REFCNT = 1
FLAGS = (PADTMP,IOK,pIOK)
IV = 0

Otherwise '... if %hash;' could never yield a false value since the
expression isn't evaluated in a numeric context.

Tassilo Von Parseval

unread,
Dec 3, 2003, 8:50:31 AM12/3/03
to Rafael Garcia-Suarez, sch...@pobox.com, perl5-...@perl.org
On Wed, Dec 03, 2003 at 11:20:12AM +0100 Rafael Garcia-Suarez wrote:
> Tassilo von Parseval wrote:
> >
> > Well, wouldn't that mean that there should be a mechanism for the
> > programmer to control the behaviour of a tied hash in scalar context,
> > like having the proposed SCALAR method?
>
> I think that's a sensible idea. And add a default SCALAR method
> to Tie::Hash or Tie::StdHash. And croak only for tied hashes used
> in scalar context and that don't provide a SCALAR method.

Just out of fun I prepared a very preliminary patch against a freshly
synced bleadperl. It doesn't yet do the additions to Tie::Hash and the
various PODs. Maybe someone can have a look at it and see whether it is
usable at all in which case I could prepare a comprehensive patch. Also,
I don't have any experience with patches that touch embed.fnc such as
this one. So this needs to be reviewed as well.

The patch adds a public function Perl_hv_scalar() to the perlapi so that
tied hashes can also be evaluated in scalar context from XS. I don't
know whether this is useful. Perl_magic_scalarpack() could probably also
be triggered directly from pp.c and pp_hot.c respectively which would
save one function frame.

patch

Abigail

unread,
Dec 3, 2003, 2:32:30 PM12/3/03
to Elizabeth Mattijsen, tassilo....@post.rwth-aachen.de, Michael G Schwern, Rafael Garcia-Suarez, perl5-...@perl.org


Yes. From 'man perldata':

If you evaluate a hash in scalar context, it returns false
if the hash is empty. If there are any key/value pairs,
it returns true; more precisely, the value returned is a
string consisting of the number of used buckets and the
number of allocated buckets, separated by a slash.

It has been documented to do so for as long as I can remember.

Abigail

Yitzchak Scott-Thoennes

unread,
Dec 3, 2003, 9:23:02 PM12/3/03
to Rafael Garcia-Suarez, sch...@pobox.com, perl5-...@perl.org
On Wed, Dec 03, 2003 at 02:50:31PM +0100, Tassilo von Parseval <tassilo....@post.rwth-aachen.de> wrote:
> On Wed, Dec 03, 2003 at 11:20:12AM +0100 Rafael Garcia-Suarez wrote:
> > Tassilo von Parseval wrote:
> > >
> > > Well, wouldn't that mean that there should be a mechanism for the
> > > programmer to control the behaviour of a tied hash in scalar context,
> > > like having the proposed SCALAR method?
> >
> > I think that's a sensible idea. And add a default SCALAR method
> > to Tie::Hash or Tie::StdHash. And croak only for tied hashes used
> > in scalar context and that don't provide a SCALAR method.
>
> Just out of fun I prepared a very preliminary patch against a freshly
> synced bleadperl. It doesn't yet do the additions to Tie::Hash and the
> various PODs. Maybe someone can have a look at it and see whether it is
> usable at all in which case I could prepare a comprehensive patch. Also,
> I don't have any experience with patches that touch embed.fnc such as
> this one. So this needs to be reviewed as well.
>
> The patch adds a public function Perl_hv_scalar() to the perlapi so that
> tied hashes can also be evaluated in scalar context from XS. I don't
> know whether this is useful. Perl_magic_scalarpack() could probably also
> be triggered directly from pp.c and pp_hot.c respectively which would
> save one function frame.

My eyeballs say the patch is ok. I like the idea of taking what I
view as "cold" code out of pp_hot.c. I'd like to see pp_padhv and
pp_padav moved into pp_hot.c, though.

The one caveat is that this will produce a more confusing error
message if SCALAR isn't implemented. I'd like to see the following:

if SCALAR is available, use it.
elsif HvEITER is 0, call FIRSTKEY
else croak with the current error message

I'd bet this would cover almost all existing cases of scalar(%tied_hash).

Tassilo Von Parseval

unread,
Dec 4, 2003, 2:46:35 AM12/4/03
to Yitzchak Scott-Thoennes, Rafael Garcia-Suarez, sch...@pobox.com, perl5-...@perl.org

I thought about maintaining the current error message as well. On the
other hand, right now you get the error message that you'd get when not
implementing one of the other special methods:

ethan@ethan:~$ Projects/bleadperl/perl
package Tie;
sub TIEHASH { bless {}=>__PACKAGE__ }
package main;
tie my %hash => 'Tie';
print scalar(%hash);
__END__
Can't locate object method "SCALAR" via package "Tie" at - line 5.

The error message we have right now in blead is a temporary thing as I
understood it. Up to 5.8.2, scalar on tied hashes returns 0.

So for 5.10.0 we could just do it without any special error (as the
above code demonstrates) or we could call SCALAR when it's present and
otherwise return 0. The thing that I don't like about the latter (or
blead's current error message) is that it treats SCALAR as special which
shouldn't be the case once it made it into the core.

0 new messages