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

Re: [PATCH for discussion] new feature: clamp %hash

Thread Previous | Thread Next
Michael G Schwern
August 5, 2001 13:22
Re: [PATCH for discussion] new feature: clamp %hash
Message ID:
On Tue, Jul 31, 2001 at 09:26:03AM -0500, Miller, Scott L wrote:
> > Just want to reiterate the point that if we can change the value of a
> > key, we should be able to delete the key *and* reinstate it.
> > 
> >     my %hash = (a => 1, b => 2);
> >     readonly %hash;
> >     $hash{a} = "foo";
> >     delete $hash{a};
> >     $hash{a} = "bar";
> Probably a newbie type question, but:
> Why would you want to do this, when you can simply say:
> $hash{a}="foo";
> $hash{a}="bar";
> and get the same affect?  It seems to me that it would be much more
> expensive to delete the key between the assignments...

Sorry, the example was just a simple illustration of the expected
behavior.  I was just pointing out that you can reinstate a deleted
key on a readonly hash (assuming it's part of the allowed set).

There are times when the difference between "exists $hash{a}" and
"defined $hash{a}" become important (otherwise, exists() wouldn't
exist).  If it doesn't exist, it means you never put anything in that
key.  If it's not defined, it means you put something in that key and
the value happens to be not defined.

My primary example, and the one I slammed into with pre-5.6
pseudo-hashes, is this:

Let's say you have an object (modeled as a hash ref) which represents
the columns of a table in a database (a la Class::DBI).  You only grab
the values from the database when they are requested.  A very simple
way to handle this is:

    sub get {
        my($self, $col) = @_;
        $self->{$col} = $self->_fetch($col) 
            unless exists $self->{$col};

        return $self->{$col};

Values in the database may be null (undef), so I must use exists().
Presumably I've set up $self so that it's a readonly hash with keys
for all the columns in the table, but I've deleted all those keys when
I initialize the object.

    sub new {
        my($class) = shift;

        # Presumably this sort of thing would be encapsulated.
        my $self = { map { $_ => 0 } $class->columns };
        readonly $self;
        delete $self->{$_} foreach keys %self;

        return bless $self, $class;

So a nice, new, fresh object will be a readonly hash who's keyset is
the names of all the columns in the table.  Then when I say:

    print $self->get("foo");

for the first time, $self->{foo} does not exist, it goes and checks
the database.  Second time, $self->{foo} exists, and it just returns
its value.

Pseudo-hashes currently allow this sort of behavior and It Is Good.
Without it, I would have to maintain a seperate hash of what columns
I've accessed and which I haven't.  Not a huge problem, but rather
annoying and double the memory.

Essentially, delete/exists is just bookkeeping.  It shouldn't be
effected by or effect the clamped nature of the hash.
Clamping/readonly is for protecting the keyset, not the values (at
least in this context).  If you can say this:

    %foo = (a => 1, b => 2);
    $foo{a} = "this";
    readonly %foo;
    $foo{a} = undef;

ie. you can alter the value of 'a' after its been clamped.  Then you
may as well be able to delete 'a' entirely.  This also has the nice
effect of making keys() and values() work properly.

My experience with pseudo-hashes says this is the Right Thing To Do.


Michael G. Schwern   <>
Perl6 Quality Assurance     <>	     Kwalitee Is Job One

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