[% setvar title Common attribute system to allow user-defined, extensible attributes %]

This file is part of the Perl 6 Archive

Note: these documents may be out of date. Do not use as reference!

To see what is currently happening visit http://www.perl6.org/


Common attribute system to allow user-defined, extensible attributes


  Maintainer: Nathan Wiger <nate@wiger.org>
  Date: 28 Sep 2000
  Last Modified: 1 Oct 2000
  Mailing List: perl6-language@perl.org
  Number: 337
  Version: 2
  Status: Frozen


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 :attr1 and :attr2 are supposed to do. This takes a shot at it, since this could simplify the implementation of RFC 188, RFC 336, RFC 163, and others.

Currently, the attributes module can be used to set and retrieve these attributes. However, the current MODIFY_ATTRIBUTES and 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 use optimize pragma.


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 :fluffy would trigger the execution of a specific attribute handler, which could make the necessary changes to the variable.

This would allow RFC 188, which proposes new private and public keywords, to instead be implemented as attributes. This is perhaps more appropriate since these do not alter lexical scope (unlike my and 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 :private and :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 my or our declarations; see RFC 279 for details.


The easiest way I see is to change the 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 :fluffy on an instance of Foo would just result in it being stored as text retrievable via attributes::get or some other means. On declaration of :size('big'), though, the 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 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 use optimize pragma), to the data for that object, or something else.

Note that you could even add a 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.


This alters the current meaning of attribute handling. From the man page on 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

Like Michael Schwern said in RFC 241, "You pays your money and you takes your chances." ;-)


RFC 279: my() syntax extensions and attribute declarations

RFC 218: my Dog $spot is just an assertion

RFC 303: Keep use less, but make it work.

RFC 270: Replace XS with the 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