This and other RFCs are available on the web at http://dev.perl.org/rfc/ =head1 TITLE Common attribute system to allow user-defined, extensible attributes =head1 VERSION Maintainer: Nathan Wiger <[EMAIL PROTECTED]> Date: 28 Sep 2000 Last Modified: 1 Oct 2000 Mailing List: [EMAIL PROTECTED] Number: 337 Version: 2 Status: Frozen =head1 ABSTRACT Camel-3 and others have proposed a syntax for declaring variables like so: my type $var :attr1 :attr2 = $val; However, nobody has firmly nailed down what C<:attr1> and C<:attr2> are supposed to do. This takes a shot at it, since this could simplify the implementation of B<RFC 188>, B<RFC 336>, B<RFC 163>, and others. Currently, the C<attributes> module can be used to set and retrieve these attributes. However, the current C<MODIFY_ATTRIBUTES> and C<FETCH_ATTRIBUTES> subs are not really fine-grained enough to give really good control. It would be nice to be able to call specialized, delegateable and inheritable subs to handle attributes. Furthermore, these attribute handlers should be able to alter Perl's internals somewhat, perhaps through the C<use optimize> pragma. =head1 DESCRIPTION Attributes should be able to access some type of core hooks so that they can be defined by the user and extended arbitrarily. For example, in pseudocode, a user should be able to say something like this: package Dog; attr fluffy { causes numeric contexts to fail; results in stringification appending "--and fluffy"; } Then, if a user does the following: my Dog $spot :fluffy = "happy"; print "$spot"; # "happy--and fluffy"; $spot++; # fails So, the declaration of C<:fluffy> would trigger the execution of a specific attribute handler, which could make the necessary changes to the variable. This would allow B<RFC 188>, which proposes new C<private> and C<public> keywords, to instead be implemented as attributes. This is perhaps more appropriate since these do not alter lexical scope (unlike C<my> and C<our>), but rather change properties of the variables themselves: package __ALL__; # some type of builtin global declaration attr private { attachable to hashes and hash keys only; marks entire hash as non-autovivifying; marks specific entry as private to the package; allows duplication of keys in different packages; leaves any other entries public; } attr public { attachable to hashes and hash keys only; marks specific entry as accessible by all packages; would take the entry out of the package symbol table; } In your code, then, you could use the C<:private> and C<:public> attributes to modify your variables: sub new { my ($class, %self) = @_; bless \%self :private, $class; $self{seed} = rand; # dies, can't autovivify $self{seed} :private = rand; # okay $self{seed} = rand; # now okay } In addition, perhaps we have a BigInt class that we need to be able to modify: package BigInt; attr 128bit { attachable to any variable; causes exception if 128 bits not supported; results in huge memory preallocation; does other neato stuff too; } Again, in your code: my BigInt $x :128bit; This would invoke the attribute to modify the variable's properties internally. By having some type of attribute-specific declaration method, the attribute system could be modifiable at will, allowing for native access to variable manipulation without the need to compile a new version of Perl. This would allow those who want to to warp Perl OO into Java or Python or C++ without these features having to be either widely used or embedded in core. A base class could simply define attribute handlers which other classes could then inherit from. Attributes would be inherited just like subs. Attributes are not necessarily tied to C<my> or C<our> declarations; see B<RFC 279> for details. =head1 IMPLEMENTATION The easiest way I see is to change the C<attributes> pragma into a pre-declaration pragma instead, something like: package Foo; use attributes fluffy => 'DEFAULT', size => \&SIZE_ATTR, UNKNOWN => \&ATTR_HANDLER; So, the declaration of C<:fluffy> on an instance of C<Foo> would just result in it being stored as text retrievable via C<attributes::get> or some other means. On declaration of C<:size('big')>, though, the C<SIZE_ATTR(\$var, 'big')> sub from the class would be called. That is, a reference to the variable being altered would be the first arg, and the attribute arguments would be passed in by value. Any unknown attributes would be thrown to the C<ATTR_HANDLER> sub, which would take the name of the attribute as the first arg, and then the other args would look like any other handler. For example: my Foo $bar :baz('likely'); # Foo->ATTR_HANDLER('baz', \$bar, # 'likely') The name of the unknown attribute is the first arg so it can easily be shifted off. In both scenarios, the attributes should always be retrievable at a later time. However, the declaration of an attribute should also be able to trigger the execution of a specific sub that can make changes to internals (perhaps through the C<use optimize> pragma), to the data for that object, or something else. Note that you could even add a C<use strict 'attrs'> pragma that dictated you could only use predeclared attributes. This could help catch mistyping of important ones: package Parallel; use attributes slippery => \&FALL_OFF; package main; use strict 'attrs'; my Parallel $bar :slipery; # raise exception Here, we've caught a typo that might result in badness later. =head1 MIGRATION This alters the current meaning of attribute handling. From the man page on C<attributes.pm>: WARNING: the mechanisms described here are still experimental. Do not rely on the current implementation. In particular, there is no provision for applying package attributes to 'cloned' copies of subroutines used as closures. (See the Making References entry in the perlref manpage for information on closures.) Package- specific attribute handling may change incompatibly in a future release. Like Michael Schwern said in RFC 241, "You pays your money and you takes your chances." ;-) =head1 REFERENCES RFC 279: my() syntax extensions and attribute declarations RFC 218: C<my Dog $spot> is just an assertion RFC 303: Keep C<use less>, but make it work. RFC 270: Replace XS with the C<Inline> module as the standard way to extend Perl. RFC 188: Objects : Private keys and methods RFC 163: Objects: Autoaccessors for object data structures RFC 336: use strict 'objects': a new pragma for using Java-like objects in Perl