[Chicago-talk] what's with these attributes?

Steven Lembark lembark at wrkhors.com
Tue Mar 30 11:44:31 CST 2004


> Hence, I poked around perlfunc and
> Attribute::Handlers' POD, but didn't really get any
> answers. As best as I can tell, they're used as a
> gimmick to associate some extra information about some
> piece of data (variable, code, etc.) at some point
> after compilation or declaration.
> Class::Declare::Attributes looks like a fairly nifty
> use of them. Did I get it right? Are there any other
> good references on the subject? The docs I've found
> have seemed a little sparse.
>
> As a side note, in Attribute::Handlers' docs, I saw
> this tidbit:
>
> my LoudDecl $loudobj : Loud;
>
> and some mutterings about how the attribute called
> corresponds to the package in which the variable is
> typed (LoudDecl, in this case). Now this is a syntax
> that's complete new to me. Is it strictly something
> governing which attributes to call? Or is it useful in
> other instances?

Fuzzy memory from TPJ/Damian: Idea came partly out of
threading, which is where the oriignal attributes were
used for shared/exclusive code.

Attribute handlers extends the basic idea so that you
can have handlers for synchronous events. In that
sense they are an extension of the tie mechanism or
the BEGIN/INIT/.../END blocks that handle program
lifecycle events.

>From the A::H docs:

       This creates a handler for the attribute ":Loud" in the
       class LoudDecl.  Thereafter, any subroutine declared with
       a ":Loud" attribute in the class LoudDecl:

               package LoudDecl;

               sub foo: Loud {...}

       causes the above handler to be invoked, and passed:

>From the sound example, say that the "Loud" handler
has code in it that turns up the volume temporarily.


	sub Loud :ATTR
	{
		# turns up the volume to a preset level.
		...
	}

In this case:

   The data argument passes in the value (if any) associated
   with the attribute. For example, if &foo had been
   declared:

		   sub foo :Loud("turn it up to 11, man!") {...}

   then the string "turn it up to 11, man!" would be passed
   as the last argument.

Now, instead of having to call "Loud" every time
your voder needs to up the volume you just declare
the sub's with a "Loud" attribute:

	sub drat :Loud
	{
		say 'Drat!';
	}

or

	sub exclaim :Loud( 99 )
	{
		say shift || "Gak";
	}

Whoemever writes "drat" doesn't have to know about
the Loud sub, what to pass it, etc. All they have
to know is that "Loud" is an attribute of what they
are doing. The syntax is also a bit more declaritive
than burying a "setvolume( LOUD )" call in the code.

This is rather nice for variables. Say you have a
data structure that has to be initialized based on
an external file. You can use:

	my @valuz :Default;

or, better yet,

	my @valuz :Default( $defaultz );

The "Default" handler can then do whatever it needs
to massage $defaults into shape for an array of
values. With typed handlers for scalar, array,
etc, you can guarantee that the variables are
given reasonable values and/or initialized.

There is no reason you can't replace all of this
stuff with explicit subroutine calls. The results
with attributes tend to look cleaner, however.

Typed lexicals just allow you to choose at compile
time into which class the handler dispatches your
call.

Real-wrold example: say you have older code that passes
everything as arrays, the arrays get large, and now
you want to pass them as referents. The new stuff is
clean, but noone has time to go back and find every
example of the older code. You can create an attribute
handler for arrays that does nothing more than replace
them in the symbol table with scalars:

    *glob = \@{*glob}; # coudle-check my syntax on this

at that point the array handler can be used to force
incomming arguments to the correct type -- possibly
logging the fact.

You could also use these for Class::Contract-ish front
ends:

    sub foo :Contract( 'Marry' )

could call a contract handler, telling that the marriage
contract is in force (default with no arg's is the "foo"
contract taken from the sub's name).

Again, there is nothing here you couldn't do without A::H,
but declaring the sub's this way makes it a bit more
obvious what is going on [once you know about attributes].

The phase-specific handlers are nice in allowing code
reuse for phases. The "bookends" example allows, say,
cleanup code to remove cruft files before and after
execution.

Tying variables with A::H syntax is also less error
prone than the normal syntax:

    my $next : Cycle(['A'..'Z']);     # $next is now a tied variable


--
Steven Lembark                               2930 W. Palmer
Workhorse Computing                       Chicago, IL 60647
                                            +1 888 359 3508



More information about the Chicago-talk mailing list