develooper Front page | perl.perl5.porters | Postings from October 2001

Re: [PATCH] core-only patch for clamp/readonly hashes

Thread Previous | Thread Next
From:
Michael G Schwern
Date:
October 31, 2001 14:33
Subject:
Re: [PATCH] core-only patch for clamp/readonly hashes
Message ID:
20011031173325.E2445@blackrider
On Wed, Oct 31, 2001 at 11:59:04PM +0100, Rafael Garcia-Suarez wrote:
> I'm a little confused by the distinction between 'existing keys' and
> 'allowed keys'. Please excuse this naive question from someone jumping
> into this threads : can't those two notions be merged, for
> simplicity? (In this case deleting a key from a restricted hash will be
> always disallowed). In other words: what is this distinction useful for?

This comes up periodically.  Assuming we're talking about fixed-key
set hashes (ie. the keyset is fixed but not the values of those keys).
Fixed-value hashes is something else.

The issue is that there needs to be a way to distinguish between
what's defined, what's not there at all and what's allowed.

    defined $hash{foo};
    exists  $hash{foo};
    allowed $hash{foo};

Why?  Consider 5.005_03 pseudo-hashes, there exists() reported if the
key was allowed or not.

    defined $ph->{foo};
    exists $ph->{foo} == allowed $ph->{foo}.

You lose the ability to distinguish between a key that has no value
and a key that is undefined.

First, you have a consistency problem.  What's the result of this
function:

    sub foo {
        my($hash) = shift;
        delete $hash->{foo};
        print "Deleted" unless exists $hash->{foo};
    }

You'd think it would always print "Deleted", but not if $hash uses
exists() as allowed().

As a more practical problem, the existance of a key and the definition
of its value (exists/defined) is important to many of the applications
of a hash with a read-only keyset.  Consider mapping a database row to
a hash.  The keyset is the set of columns.  Now what if you wanted to
load each key only on demand?

    sub get {
        my($self, $key) = @_;

        $self->_retrieve_from_db($key) unless exists $self->{$key};
        return $self->{$key};
    }

If exists == allowed, that won't work as it will always be true
(assuming $key is allowed).  What do you do?  Can't use defined(),
otherwise how are you going to represent NULL values?  You have to do
something kludgy like keep a second hash around:

    sub get {
        my($self, $key) = @_;

        $self->_retrieve_from_db($key) unless $self->{_retrieved}{$key};
        return $self->{$key};
    }

Double your memory, double your fun!


Yes, I feel strongly about this.  I hit this problem with Class::DBI
and 5.005 pseudo-hashes (people may remember the old "_safe_exists"
function) because exists() == allowed().

This is why exists() and delete() works on arrays.  Array values which
are not initialized, or have been deleted, have PL_sv_undef as their
values, IIRC.  This allows the following to work:

    $array[42] = "foo";
    print "Doesn't exist" unless exists $array[23];

exists() sees that $array[23] has PL_sv_undef as it's value and
returns value.  Clamped hashes could probably do the same thing.


-- 

Michael G. Schwern   <schwern@pobox.com>    http://www.pobox.com/~schwern/
Perl6 Quality Assurance     <perl-qa@perl.org>	     Kwalitee Is Job One
gumballs have no paste
Tim's balls are so damn pasty
bend over and squeal
	-- |siv|

Thread Previous | Thread Next


nntp.perl.org: Perl Programming lists via nntp and http.
Comments to Ask Bjørn Hansen at ask@perl.org | Group listing | About