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

Re: restricted hashes, and other readonlyness (was "clamp...")

Thread Previous | Thread Next
From:
Nick Ing-Simmons
Date:
November 1, 2001 06:14
Subject:
Re: restricted hashes, and other readonlyness (was "clamp...")
Message ID:
20011101141414.6376.7@bactrian.elixent.com
Jeffrey Friedl <jfriedl@yahoo.com> writes:
>Okay, I got rid of the union, the 'realkeys' stuff, added what was
>needed for array readonlyness, and generally tidied up.
>
>I've dropped the "clamp" nomenclature, in favor of "pseudo-enumerated" or
>"restricted" hashes.  (I still don't care what we call it, but I've got
>to use something....)

I think just "enumerated" will be fine - but see below.

>
>
>So, here's the current status after the appended patch:
>
> SCALARS
> -------
>   Readonlyness can be set and cleared.
>   (as before -- no changes with ths patch)
>
> ARRAYS
> ------
>   Readonlyness can be set and cleared.
>   An array that is SvREADONLY prohibits anything that would
>   change the size of the array, and the deletion of elements.
>
> HASHES
> ------
>   Two new bits: SvREADONLY and HvPSEUDO_ENUMERATED
>
>   A hash that is SvREADONLY (but not HvPSEUDO_ENUMERATED) has a readonly
>   set of keys: no adding new keys or deleting existing keys.
>
>   A hash that is SvREADONLY and HvPSEUDO_ENUMERATED is a "restricted hash"
>   or a "pseudo-enumerated hash".  This means that the hash has a set of
>   "approved" keys, and all operations are allowed with those keys.

This still feels wrong way round to me - more restricted should meant
set more bits - that way we only need to test more bits if we are doing
something in the inner set.

    Thus
     $foo{'Gibberish'} = 1;
    is not allowed in either case - so we should only need one test:

    if (Enumerated(HV)) {
      die "Cannot do that";
    }


>   Any access, other than exists(), with a key that is not approved results
>   in an error.

    I agree with Graham that exists on a non-approved key should also be
    an error.

>
>   A hash that is HvPSEUDO_ENUMERATED (and not SvREADONLY) may add and delete
>   keys freely, but read access of a non-existant key is an error. This is
>   a less restrictive form of a pseudo-enumerated hash that says "you can
>   add elements freely, but if you're going to try to read an element, it
>   had better actually be there."

    Oh dear a 4th type which needs a name - say "Picky" :-(
    With your sense of bits we now have:
       RO EN
       0   0   - normal
       0   1   - "Picky"
       1   0   - non-deletable Enumerated
       1   1   - deletable Enumerated

I can see some value in 'picky' hashes but I am sure we don't have
concensus on them! We could (in principle) coin some pragma:
use strict 'keys';
to cover that.

As far as _I_ am concerned - I am convinced we need one of the "Enumerated"
types. I don't really care which of the two it is. The non-deletable
variant is easier to explain (cf 'w' bit on a UNIX directory), and avoids
the issue of what C<keys> returns.
The deletable variant is possibly of wider use (e.g. Michael Schwern's
db cache example) but I am as yet unconvinced that case is common enough
(compared to the 'struct' case) to be worth the extra bit and hassle of
defining semantics of C<keys> etc.

If we only have one variant we only need one bit, and it can be SvREADONLY.

>
>   exists() now returns:
>       1      -- is there
>       ''     -- not there, and not allowed.
>       undef  -- not there, but could be. (Doesn't exist, but is "allowed")
>   Previously, it returned only 1 and ''.

If we don't make exists on a non-allowed key an error,
I would reverse the bottom two - that way the the typo is likely
to trigger 'Use of undefined' warning.

>
>
>   keys(), values(), and each() return data only for keys that actually
>   exist(). They ignore, for example, keys that are "approved" but don't
>   yet exist. In a scalar context, it returns the number of keys that
>   actually exist.  (It's left to an XS module to provide a way to get
>   the full list of approved keys.)

You know I differ on this one ;-)

>
>   For *any* hash, if...
>
>        my @K     = keys %HASH;
>        my @V     = values %HASH;
>        my $count = 0;
>        while (my ($key,$val) = each %HASH) {
>           $count++;
>        }
>
>   then these are always true:
>
>      keys(%HASH) == @K;
>      keys(%HASH) == @V;
>      keys(%HASH) == $count;

All very nice - but why should a "struct" (enumerated hash) have to have
same semantics as a normal hash?  To me having keys return the allowed
set (assuming we allow deletes) is more useful than the equivalences
above. Given that there are three ways of doing something on a hash
why not subsume one of them for extra sematics of a struct-oid?

(Another way of looking at this might be to say
   scalar keys %hash    ; # allowed
   scalar values %hash  ; # existing
)

>
>
>There are (at least) two issues that remain:
>
>* Doesn't use the value for the SVh_PSEUDO_ENUMERATED flag that Nick wanted.
>  Easy to update when he says what value to use.

My objection was not the use of a particular bit number, but the positioning
of the #define in the code relative to #define-s for adjacent bits.
That said SvFAKE might be appropriate - see below.

>
>* Arrays -- I implemented the semantics that people asked for (lock the
>  size of the array), but I see a problem in that there's no way to have a
>  totally readonly array. With hashes, if you want a totally readonly hash,
>  you merely set SvREADONLY on the hash, and on each of its values. But
>  with an array, if you do that, you can still put values to empty slots in
>  a sparce array:
>       my @a = (1,2,3);
>       $a[100] = 'big';
>       magically_make_totally_readonly @a;
>       $a[50] = 'half';       <-- should not be allowed, but currently is
>
>  Would it make sense to also disallow the creation of embedded elements
>  that don't currently exist()?

The exists concept in arrays did/does not have a well defined meaning.
I seem to recall "exists" being hacked in at one point to support
the old pseudo-hash stuff. In addition there is really old (perl4 ?)
concept of arrays which are sparse in some sense I don't fully
understand (via SvFAKE?).

Note that existing SvFAKE bit _MAY_ be a suitable bit to use for
HvENUMERATED if we really need it.

--
Nick Ing-Simmons
http://www.ni-s.u-net.com/



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