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

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

Thread Previous | Thread Next
Michael G Schwern
October 31, 2001 14:33
Re: [PATCH] core-only patch for clamp/readonly hashes
Message ID:
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

    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   <>
Perl6 Quality Assurance     <>	     Kwalitee Is Job One
gumballs have no paste
Tim's balls are so damn pasty
bend over and squeal
	-- |siv|

Thread Previous | Thread Next Perl Programming lists via nntp and http.
Comments to Ask Bjørn Hansen at | Group listing | About