Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

When should I use subroutine attributes?

Tags:

I don't grok Perl subroutine attributes at all.

I have never seen them in actual code and perldoc perlsub and the perldoc attributes fail to answer my questions:

  • What are attributes useful for?
  • What do they bring to the table that is not already present in Perl best practices?
  • Are there any CPAN modules (well-known or otherwise) that make use of attributes?

It would be great if someone could put together a detailed example of attributes being used the way they should be.


For those who are as clueless as me, attributes are the parameters after the colon in the attributes SYNOPSIS examples below:

sub foo : method ; my ($x,@y,%z) : Bent = 1; my $s = sub : method { ... };  use attributes ();  # optional, to get subroutine declarations my @attrlist = attributes::get(\&foo);  use attributes 'get'; # import the attributes::get subroutine my @attrlist = get \&foo; 
like image 732
Zaid Avatar asked Dec 10 '11 10:12

Zaid


People also ask

Why is subroutine important in Perl?

A Perl function or subroutine is a group of statements that together perform a specific task. In every programming language user want to reuse the code. So the user puts the section of code in function or subroutine so that there will be no need to write code again and again.

Which is the proper way to define a subroutine?

In computer programming, a subroutine is a sequence of program instructions that performs a specific task, packaged as a unit. This unit can then be used in programs wherever that particular task should be performed.

What is subroutine in Perl explain passing agreements to subroutine?

Subroutines are blocks of code that can be reused across programs. They are the same as functions or user-defined functions in Perl. We can either define a subroutine in the same program or import it from another file using the use , do , or require statements.


2 Answers

Attributes allow you annotate variables to perform auto-magic behind the scenes. A similar concept is java annotations. Here is a small example that might help. It uses Attribute::Handlers to create the loud attributes.

use Attribute::Handlers;  sub UNIVERSAL::loud : ATTR(CODE) {     my ( $pkg, $sym, $code ) = @_;     no warnings 'redefine';     *{$sym} = sub {         return uc $code->(@_);     }; }  sub foo : loud {     return "this is $_[0]"; }  say foo("a spoon"); say foo("a fork"); 

Whenever a sub is declared with the loud attribute the UNIVERSAL::loud callback triggers exposing meta-information on the sub. I redefined the function to actually call an anonymous sub, which in turn calls the original sub and passes it to uc

This outputs:

THIS IS A SPOON THIS IS A FORK 

Now let's looks a the variable example from the SYNOPSIS:

my ($x,@y,%z) : Bent = 1; 

Breaking this down into small perl statement without taking into account attributes we have

my $x : Bent $x = 1;  my @y : Bent @y = 1;  my %Z : Bent %z = 1; 

We can now see that each variable has been attributed the Bent annotation in a concise way, while also assigning all variables the value 1. Here is a perhaps more interesting example:

use Attribute::Handlers; use Tie::Toggle;  sub UNIVERSAL::Toggle : ATTR(SCALAR) {     my ($package, $symbol, $referent, $attr, $data, $phase) = @_;     my @data = ref $data eq 'ARRAY' ? @$data : $data;     tie $$referent, 'Tie::Toggle', @data; }  my $x : Toggle;  say "x is ", $x; say "x is ", $x; say "x is ", $x; 

Which outputs:

x is  x is 1 x is  

You can use this to do logging, create test annotations, add type details to variables, syntactic sugar, do moose-ish role composition and many other cool things.

Also see this question: How do Perl method attributes work?.

like image 120
JRideout Avatar answered Jan 29 '23 17:01

JRideout


  • What are attributes useful for?

It is a way to pass some additional information (the attribute) about a variable or subroutine.

You can catch this information (the attribute) as a string ( at COMPILE TIME !) and handle it however you like. You can generate additional code, modify stashs ... . It is up to you.

  • What do they bring to the table that is not already present in Perl best practices?

Sometimes it makes life easier. See example below.

Some people use it. Do a : find . -name *.p[ml] | xargs grep 'use attributes;' at your perl installation path to look at packages using attributes. Catalyst extensively uses attributes to handle requests based on the given path.

Example :

Say you like to execute subroutines in a certain order. And you want to tell the subroutine when it has to execute ( by a run number RUNNR ). Using attributes the implementation could be :

#!/usr/bin/env perl  use strict; use warnings;  use Runner;     # immplements the attribute handling  # some subroutines to be scheduled : # attibutes automatically filling @$Runner::schedule  sub func_a : RUNNR(2) {return "You called func_a !"}; sub func_b : RUNNR(1) {return "You called func_b !"}; sub func_c : RUNNR(3) {return "You called func_c !"};  # run the subroutines according to the their RUNNR sub run {     # @$Runner::schedule holds the subroutine refs according     # to their RUNNR     foreach my $func (@$Runner::schedule) {        if ( defined $func ) {          print "Running : $func --> ", $func->(), "\n";        }     } }  print "Starting ...\n\n"; run(); print "\nDone !\n"; 

The attribute handling is in package Runner using the MODIFY_CODE_ATTRIBUTES hook.

package Runner;  use strict; use warnings;  use attributes;  BEGIN {     use Exporter ();                                                                      our (@ISA, @EXPORT);             @ISA         = qw(Exporter);                      @EXPORT      = qw(&MODIFY_CODE_ATTRIBUTES);    # needed for use attributes;     }  # we have subroutines with attributes : <type> is CODE in MODIFY_<type>_ATTRIBUTES # MODIFY_CODE_ATTRIBUTES is executed at COMPILE TIME ! try perl -c <prog_name> to prove it :-)  sub MODIFY_CODE_ATTRIBUTES {     # for each subroutine of a package we get     # the code ref to it and the attribute(s) as string     my ($pckg, $code_ref, @attr) = @_;      # whatever you like to do with the attributes of the sub ... do it     foreach my $attr (@attr) {         # here we parse the attribute string(s), extract the number and          # save the code ref of the subroutine         # into $Runner::schedule array ref according to the given number         # that is how we 'compile' the RUNNR of subroutines into          # a schedule         if ( $attr =~ /^RUNNR\((\d+)\)$/ ) {                 $Runner::schedule->[$1] = $code_ref;              }     }     return(); # ERROR if returning a non empty list }  1; 

The output will be :

Starting ...  Running : CODE(0x129c288) --> You called func_b ! Running : CODE(0x129c2b8) --> You called func_a ! Running : CODE(0x12ed460) --> You called func_c !  Done ! 

If you really want to understand what attributes do and when what happens you have to 'perldoc attributes', read it step by step and play with it. The interface is cumbersome but in principle you hook in at compile time and handle the information provided.

like image 29
katastrophos Avatar answered Jan 29 '23 17:01

katastrophos