This and other RFCs are available on the web at
  http://dev.perl.org/rfc/

=head1 TITLE

Automatic accessors for hash-based objects

=head1 VERSION

 Maintainer: James Mastros <[EMAIL PROTECTED]>
 Date: 25 Aug 2000
 Version: 1
 Mailing List: [EMAIL PROTECTED]
 Number: 163

=head1 ABSTRACT

This RFC proposes an attribute, C<:accessible> L<[1]> that may be applied
to hash keys to make them accessible to the outside as C<$obj-E<gt>foo>,
this being (largely) equivalent to C<$obj-E<gt>{foo}>.

=head1 DESCRIPTION

The C<:accessible> attribute on a hash key L<[2]> would make it such
that, given a blessed hashref C<$obj>, C<$obj-E<gt>foo> can refer to the
same variable as C<$obj-E<gt>{foo}>.  Note that I say "can", because
whether or not it I<will> depends on the parameters to the accessible
attribute.

The phrase $obj-E<gt>foo will be referred to as an accessor for the
rest of this document, and an autoaccessor if it is not a real method,
but emulated via the :accessible mechanism.  The value part of the
hash element that defines the autoaccessor is called the
autoaccessor's value.

If the call to an autoaccessor is in list context, it returns the
single-element list containing the value of the key, just as
C<$obj-E<gt>{foo}> would.  This means that it is impossible for an
autoaccessor to ever return a list (it can return an arrayref,
though).

This hopefully isn't a problem.

If the attribute has parameters, each can be a context-permission
specifier, or a meta-attribute.

A context-permission parameter consists of an optional permission,
followed by an access type, a sequence which can repeat zero or more
times.

The permissions are:

The defined permissions are:

    '!', which forces the method call to fail, without further ado L<[5]>, and
    '+', which makes the autoaccessor handle the call
    '~', which makes the autoaccessor fail, but allow traditional ways
         of handling the method call..

The default is '+', if no permission is specified for a context.

A context with a '~' permission is the same as not specifying the
context letter at all L<[7]>, and is included only for completeness.

The context can be:

    'r' for rvalue (or 'r' for read)
    'l' for lvalue (or 'w' for write)
    'm' for mutator (which has no synonym) L<[6]>

If a letter is not present, use of the autoaccessor does not occur in
this context, but normal subs, AUTOLOAD, and inheritance are all
tried.  The letters attempt to be mnemonic with both the computer
science terms and the analogous file permissions.

The exception to this is that if the attribute is present, but has no
arguments, the default is '+r', that is the autoaccessor is used for
read access only, but mutate and write access must be through a
written lvalue sub L<[7]> L<[8]>.

In addition, there is one defined meta-attributes, which change the
way in which the autoaccessor determines the value to return.

(Note that these cannot be concatenated to the permission specs or to
each-other.)

The first is "list", which tells the autoaccessor that in list
context, it should deref its value, and then return it.  Without this,
the autoaccessor will return the ref itself, even in list context.

L<[9]>

=head1 IMPLEMENTATION

Here is one possible method, which does require changes to core (or
possibly transparent ties).

Whenever this attribute is set on a hash key, an attribute
(C<:has_accessible_keys>) is set on the hash.

Whenever method lookup fails on an object that is a hashref, the hash
would be checked for the C<:has_accessible_keys> attribute and, if
found, a lookup for the key in the thingy would occur.  If it is
found, and the :accessible attribute is found, the parameter of the
attribute would be checked, and it is processed as in DESCRIPTION
above.

The attribute on the hash is there on the assumption that it's much
faster then a key lookup.  This might not be the case.

=head1 DIAGNOSTICS

=begin perldiag

=item call to method "%s" in class %s denied by autoaccessor permissions

(F) You attempted to call an autoaccessor in a context it didn't like.
This probably means that it's impossible to do this (or the
permissions are wrong).  Check the documentation of the class mentioned.

=end perldiag

The first %s should be the method name, and the second should be ref($obj).

=begin perldiag

=item Autoaccessor '%s' attempted to deref nonref '%s'.

(F) The autoaccessor is set up to autoderef it's value, but it's value
isn't a ref.  This is probably the fault of the module writer.

=end perldiag

The first %s is the name of the autoaccessor, the second is it's value.

=head1 EXAMPLES

This example shows how much easier it would have been to write the
example on line 170 of perltoot.pod:

    package Person;
    use strict;
    
    ##################################################
    ## the object constructor (simplistic version)  ##
    ##################################################
    sub new {
        my $self  = {};
        $self->{name} :accessible('rw') = undef;
        $self->{age}  :accessible('rw') = undef;
        $self->{peers}:accessible('rw') = [];
        bless($self);           # but see below
        return $self;
    }


Note the lack of anything close to the next 15 lines of code; all of
that is taken care of with the three simple attribute settings above.



=head1 MIGRATION

There should be no migration necessary; this simply adds an attribute.
If this attribute was in use by user code previously, it may conflict,
but that seems unlikely.

=head1 FOOTNOTES

=over 4

=item [1]

It would be nice to come up with another name that I'm not constantly
spelling as :accesB<a>ble, and still have it be an adjective
describing the key (and not :autoaccessor, which would describe the
accessor, which isn't what you set the attribute on).

=item [2]

This assumes that there is some way of setting attributes on hash keys
(or hash elements).  I don't think there currently is.  I consider
this outside the scope of this RFC -- any takers?

=item [5]

Ado here being defined as checking for subs in the appropriate class
or it's ancestors, and checks for an appropriate AUTOLOAD.

=item [3]

Perhaps there should be another special case: '+r+w' implies '+m'?
It's possible that having 'm' separate from 'rw' isn't useful at all
-- would you ever want the value to be used only as a mutator?

=item [4]

Except if '~r' is the only permission mentioned, in which case it is
the same as not giving the :accessible attribute at all (except
slower!).

=item [7]

I would have said explicit, but has another definition now.  Sigh.
All the good words are taken.

=item [8]

Which I'm not going to get into, given that the entire point of this
RFC is to have a way to get the benefits of lvalue subs without much
of the headache and execution time.


=item [9]

I want some way of doing context-sensitive returns, but can't seem to
get around sticky problems -- in the case of places where you want to
specify intersecting context lists, which one gets precedence?
Remember that this is naturally an unordered hash.

=back

=head1 REFERENCES

Um, none as of now.

Reply via email to