Dan Sugalski wrote:
>
> Well, yeah, it'll sort of have to if we allow user-defined types. If you do:
> 
>    my Dog $spot : male;
> 
> then the Dog package needs to be able to fetch the attributes. I've no idea
> how that'd look--perhaps an attributes() function, a method in UNIVERSAL,
> or something like that.

There's two ways I've proposed in different RFC's. The first one
utilizes a more general framework; the second one depends on C<tie>
being used. A UNIVERSAL:: method wouldn't work because you've got to get
attributes from arrays and hashes as well. We'd probably just need an
attributes() builtin for retrieval to work really smoothly (but the
RFC's just reference attributes::get, the current method).

Anyways, here's the ideas from RFC's 337 and 319; input is still
welcome:

--

RFC 337: Common attribute system to allow user-defined,
         extensible attributes

=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.



RFC 319: Transparently integrate C<tie>

=head2 Passing arguments

Since many C<tie>d variables require that extra arguments be passed,
this RFC proposes two ways of doing this. Either could be used,
depending on a person's preference:

=head3 The general attribute style

In the attribute style, extra arguments are simply specified as
attributes, which are then passed into the C<TIE*> function as
a hashref of values. So this:

   my Apache::Session %session :Transaction;

Would be the same as this in Perl 5:

   tie %session, 'Apache::Session', { Transaction => 1 };

A bare attribute is assumed to be a switch and is simply given a value
of "1". Note that attributes allow you to specify arguments, too, so
this:

   my Dog $spot :coat('shiny') :bark('rough') :mean;

Would result in the following call:

   Dog->TIESCALAR($spot, { coat => 'shiny', bark => 'rough',
                           mean => 1 });

This form has the benefit that it makes user-defined variables appear as
transparent as builtins, and also gives the C<TIE> constructors easy
access to the attributes declared.

Reply via email to