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.