1*0Sstevel@tonic-gatepackage attributes; 2*0Sstevel@tonic-gate 3*0Sstevel@tonic-gateour $VERSION = 0.06; 4*0Sstevel@tonic-gate 5*0Sstevel@tonic-gate@EXPORT_OK = qw(get reftype); 6*0Sstevel@tonic-gate@EXPORT = (); 7*0Sstevel@tonic-gate%EXPORT_TAGS = (ALL => [@EXPORT, @EXPORT_OK]); 8*0Sstevel@tonic-gate 9*0Sstevel@tonic-gateuse strict; 10*0Sstevel@tonic-gate 11*0Sstevel@tonic-gatesub croak { 12*0Sstevel@tonic-gate require Carp; 13*0Sstevel@tonic-gate goto &Carp::croak; 14*0Sstevel@tonic-gate} 15*0Sstevel@tonic-gate 16*0Sstevel@tonic-gatesub carp { 17*0Sstevel@tonic-gate require Carp; 18*0Sstevel@tonic-gate goto &Carp::carp; 19*0Sstevel@tonic-gate} 20*0Sstevel@tonic-gate 21*0Sstevel@tonic-gate## forward declaration(s) rather than wrapping the bootstrap call in BEGIN{} 22*0Sstevel@tonic-gate#sub reftype ($) ; 23*0Sstevel@tonic-gate#sub _fetch_attrs ($) ; 24*0Sstevel@tonic-gate#sub _guess_stash ($) ; 25*0Sstevel@tonic-gate#sub _modify_attrs ; 26*0Sstevel@tonic-gate#sub _warn_reserved () ; 27*0Sstevel@tonic-gate# 28*0Sstevel@tonic-gate# The extra trips through newATTRSUB in the interpreter wipe out any savings 29*0Sstevel@tonic-gate# from avoiding the BEGIN block. Just do the bootstrap now. 30*0Sstevel@tonic-gateBEGIN { bootstrap attributes } 31*0Sstevel@tonic-gate 32*0Sstevel@tonic-gatesub import { 33*0Sstevel@tonic-gate @_ > 2 && ref $_[2] or do { 34*0Sstevel@tonic-gate require Exporter; 35*0Sstevel@tonic-gate goto &Exporter::import; 36*0Sstevel@tonic-gate }; 37*0Sstevel@tonic-gate my (undef,$home_stash,$svref,@attrs) = @_; 38*0Sstevel@tonic-gate 39*0Sstevel@tonic-gate my $svtype = uc reftype($svref); 40*0Sstevel@tonic-gate my $pkgmeth; 41*0Sstevel@tonic-gate $pkgmeth = UNIVERSAL::can($home_stash, "MODIFY_${svtype}_ATTRIBUTES") 42*0Sstevel@tonic-gate if defined $home_stash && $home_stash ne ''; 43*0Sstevel@tonic-gate my @badattrs; 44*0Sstevel@tonic-gate if ($pkgmeth) { 45*0Sstevel@tonic-gate my @pkgattrs = _modify_attrs($svref, @attrs); 46*0Sstevel@tonic-gate @badattrs = $pkgmeth->($home_stash, $svref, @attrs); 47*0Sstevel@tonic-gate if (!@badattrs && @pkgattrs) { 48*0Sstevel@tonic-gate return unless _warn_reserved; 49*0Sstevel@tonic-gate @pkgattrs = grep { m/\A[[:lower:]]+(?:\z|\()/ } @pkgattrs; 50*0Sstevel@tonic-gate if (@pkgattrs) { 51*0Sstevel@tonic-gate for my $attr (@pkgattrs) { 52*0Sstevel@tonic-gate $attr =~ s/\(.+\z//s; 53*0Sstevel@tonic-gate } 54*0Sstevel@tonic-gate my $s = ((@pkgattrs == 1) ? '' : 's'); 55*0Sstevel@tonic-gate carp "$svtype package attribute$s " . 56*0Sstevel@tonic-gate "may clash with future reserved word$s: " . 57*0Sstevel@tonic-gate join(' : ' , @pkgattrs); 58*0Sstevel@tonic-gate } 59*0Sstevel@tonic-gate } 60*0Sstevel@tonic-gate } 61*0Sstevel@tonic-gate else { 62*0Sstevel@tonic-gate @badattrs = _modify_attrs($svref, @attrs); 63*0Sstevel@tonic-gate } 64*0Sstevel@tonic-gate if (@badattrs) { 65*0Sstevel@tonic-gate croak "Invalid $svtype attribute" . 66*0Sstevel@tonic-gate (( @badattrs == 1 ) ? '' : 's') . 67*0Sstevel@tonic-gate ": " . 68*0Sstevel@tonic-gate join(' : ', @badattrs); 69*0Sstevel@tonic-gate } 70*0Sstevel@tonic-gate} 71*0Sstevel@tonic-gate 72*0Sstevel@tonic-gatesub get ($) { 73*0Sstevel@tonic-gate @_ == 1 && ref $_[0] or 74*0Sstevel@tonic-gate croak 'Usage: '.__PACKAGE__.'::get $ref'; 75*0Sstevel@tonic-gate my $svref = shift; 76*0Sstevel@tonic-gate my $svtype = uc reftype $svref; 77*0Sstevel@tonic-gate my $stash = _guess_stash $svref; 78*0Sstevel@tonic-gate $stash = caller unless defined $stash; 79*0Sstevel@tonic-gate my $pkgmeth; 80*0Sstevel@tonic-gate $pkgmeth = UNIVERSAL::can($stash, "FETCH_${svtype}_ATTRIBUTES") 81*0Sstevel@tonic-gate if defined $stash && $stash ne ''; 82*0Sstevel@tonic-gate return $pkgmeth ? 83*0Sstevel@tonic-gate (_fetch_attrs($svref), $pkgmeth->($stash, $svref)) : 84*0Sstevel@tonic-gate (_fetch_attrs($svref)) 85*0Sstevel@tonic-gate ; 86*0Sstevel@tonic-gate} 87*0Sstevel@tonic-gate 88*0Sstevel@tonic-gatesub require_version { goto &UNIVERSAL::VERSION } 89*0Sstevel@tonic-gate 90*0Sstevel@tonic-gate1; 91*0Sstevel@tonic-gate__END__ 92*0Sstevel@tonic-gate#The POD goes here 93*0Sstevel@tonic-gate 94*0Sstevel@tonic-gate=head1 NAME 95*0Sstevel@tonic-gate 96*0Sstevel@tonic-gateattributes - get/set subroutine or variable attributes 97*0Sstevel@tonic-gate 98*0Sstevel@tonic-gate=head1 SYNOPSIS 99*0Sstevel@tonic-gate 100*0Sstevel@tonic-gate sub foo : method ; 101*0Sstevel@tonic-gate my ($x,@y,%z) : Bent = 1; 102*0Sstevel@tonic-gate my $s = sub : method { ... }; 103*0Sstevel@tonic-gate 104*0Sstevel@tonic-gate use attributes (); # optional, to get subroutine declarations 105*0Sstevel@tonic-gate my @attrlist = attributes::get(\&foo); 106*0Sstevel@tonic-gate 107*0Sstevel@tonic-gate use attributes 'get'; # import the attributes::get subroutine 108*0Sstevel@tonic-gate my @attrlist = get \&foo; 109*0Sstevel@tonic-gate 110*0Sstevel@tonic-gate=head1 DESCRIPTION 111*0Sstevel@tonic-gate 112*0Sstevel@tonic-gateSubroutine declarations and definitions may optionally have attribute lists 113*0Sstevel@tonic-gateassociated with them. (Variable C<my> declarations also may, but see the 114*0Sstevel@tonic-gatewarning below.) Perl handles these declarations by passing some information 115*0Sstevel@tonic-gateabout the call site and the thing being declared along with the attribute 116*0Sstevel@tonic-gatelist to this module. In particular, the first example above is equivalent to 117*0Sstevel@tonic-gatethe following: 118*0Sstevel@tonic-gate 119*0Sstevel@tonic-gate use attributes __PACKAGE__, \&foo, 'method'; 120*0Sstevel@tonic-gate 121*0Sstevel@tonic-gateThe second example in the synopsis does something equivalent to this: 122*0Sstevel@tonic-gate 123*0Sstevel@tonic-gate use attributes (); 124*0Sstevel@tonic-gate my ($x,@y,%z); 125*0Sstevel@tonic-gate attributes::->import(__PACKAGE__, \$x, 'Bent'); 126*0Sstevel@tonic-gate attributes::->import(__PACKAGE__, \@y, 'Bent'); 127*0Sstevel@tonic-gate attributes::->import(__PACKAGE__, \%z, 'Bent'); 128*0Sstevel@tonic-gate ($x,@y,%z) = 1; 129*0Sstevel@tonic-gate 130*0Sstevel@tonic-gateYes, that's a lot of expansion. 131*0Sstevel@tonic-gate 132*0Sstevel@tonic-gateB<WARNING>: attribute declarations for variables are still evolving. 133*0Sstevel@tonic-gateThe semantics and interfaces of such declarations could change in 134*0Sstevel@tonic-gatefuture versions. They are present for purposes of experimentation 135*0Sstevel@tonic-gatewith what the semantics ought to be. Do not rely on the current 136*0Sstevel@tonic-gateimplementation of this feature. 137*0Sstevel@tonic-gate 138*0Sstevel@tonic-gateThere are only a few attributes currently handled by Perl itself (or 139*0Sstevel@tonic-gatedirectly by this module, depending on how you look at it.) However, 140*0Sstevel@tonic-gatepackage-specific attributes are allowed by an extension mechanism. 141*0Sstevel@tonic-gate(See L<"Package-specific Attribute Handling"> below.) 142*0Sstevel@tonic-gate 143*0Sstevel@tonic-gateThe setting of subroutine attributes happens at compile time. 144*0Sstevel@tonic-gateVariable attributes in C<our> declarations are also applied at compile time. 145*0Sstevel@tonic-gateHowever, C<my> variables get their attributes applied at run-time. 146*0Sstevel@tonic-gateThis means that you have to I<reach> the run-time component of the C<my> 147*0Sstevel@tonic-gatebefore those attributes will get applied. For example: 148*0Sstevel@tonic-gate 149*0Sstevel@tonic-gate my $x : Bent = 42 if 0; 150*0Sstevel@tonic-gate 151*0Sstevel@tonic-gatewill neither assign 42 to $x I<nor> will it apply the C<Bent> attribute 152*0Sstevel@tonic-gateto the variable. 153*0Sstevel@tonic-gate 154*0Sstevel@tonic-gateAn attempt to set an unrecognized attribute is a fatal error. (The 155*0Sstevel@tonic-gateerror is trappable, but it still stops the compilation within that 156*0Sstevel@tonic-gateC<eval>.) Setting an attribute with a name that's all lowercase 157*0Sstevel@tonic-gateletters that's not a built-in attribute (such as "foo") will result in 158*0Sstevel@tonic-gatea warning with B<-w> or C<use warnings 'reserved'>. 159*0Sstevel@tonic-gate 160*0Sstevel@tonic-gate=head2 Built-in Attributes 161*0Sstevel@tonic-gate 162*0Sstevel@tonic-gateThe following are the built-in attributes for subroutines: 163*0Sstevel@tonic-gate 164*0Sstevel@tonic-gate=over 4 165*0Sstevel@tonic-gate 166*0Sstevel@tonic-gate=item locked 167*0Sstevel@tonic-gate 168*0Sstevel@tonic-gateB<5.005 threads only! The use of the "locked" attribute currently 169*0Sstevel@tonic-gateonly makes sense if you are using the deprecated "Perl 5.005 threads" 170*0Sstevel@tonic-gateimplementation of threads.> 171*0Sstevel@tonic-gate 172*0Sstevel@tonic-gateSetting this attribute is only meaningful when the subroutine or 173*0Sstevel@tonic-gatemethod is to be called by multiple threads. When set on a method 174*0Sstevel@tonic-gatesubroutine (i.e., one marked with the B<method> attribute below), 175*0Sstevel@tonic-gatePerl ensures that any invocation of it implicitly locks its first 176*0Sstevel@tonic-gateargument before execution. When set on a non-method subroutine, 177*0Sstevel@tonic-gatePerl ensures that a lock is taken on the subroutine itself before 178*0Sstevel@tonic-gateexecution. The semantics of the lock are exactly those of one 179*0Sstevel@tonic-gateexplicitly taken with the C<lock> operator immediately after the 180*0Sstevel@tonic-gatesubroutine is entered. 181*0Sstevel@tonic-gate 182*0Sstevel@tonic-gate=item method 183*0Sstevel@tonic-gate 184*0Sstevel@tonic-gateIndicates that the referenced subroutine is a method. 185*0Sstevel@tonic-gateThis has a meaning when taken together with the B<locked> attribute, 186*0Sstevel@tonic-gateas described there. It also means that a subroutine so marked 187*0Sstevel@tonic-gatewill not trigger the "Ambiguous call resolved as CORE::%s" warning. 188*0Sstevel@tonic-gate 189*0Sstevel@tonic-gate=item lvalue 190*0Sstevel@tonic-gate 191*0Sstevel@tonic-gateIndicates that the referenced subroutine is a valid lvalue and can 192*0Sstevel@tonic-gatebe assigned to. The subroutine must return a modifiable value such 193*0Sstevel@tonic-gateas a scalar variable, as described in L<perlsub>. 194*0Sstevel@tonic-gate 195*0Sstevel@tonic-gate=back 196*0Sstevel@tonic-gate 197*0Sstevel@tonic-gateFor global variables there is C<unique> attribute: see L<perlfunc/our>. 198*0Sstevel@tonic-gate 199*0Sstevel@tonic-gate=head2 Available Subroutines 200*0Sstevel@tonic-gate 201*0Sstevel@tonic-gateThe following subroutines are available for general use once this module 202*0Sstevel@tonic-gatehas been loaded: 203*0Sstevel@tonic-gate 204*0Sstevel@tonic-gate=over 4 205*0Sstevel@tonic-gate 206*0Sstevel@tonic-gate=item get 207*0Sstevel@tonic-gate 208*0Sstevel@tonic-gateThis routine expects a single parameter--a reference to a 209*0Sstevel@tonic-gatesubroutine or variable. It returns a list of attributes, which may be 210*0Sstevel@tonic-gateempty. If passed invalid arguments, it uses die() (via L<Carp::croak|Carp>) 211*0Sstevel@tonic-gateto raise a fatal exception. If it can find an appropriate package name 212*0Sstevel@tonic-gatefor a class method lookup, it will include the results from a 213*0Sstevel@tonic-gateC<FETCH_I<type>_ATTRIBUTES> call in its return list, as described in 214*0Sstevel@tonic-gateL<"Package-specific Attribute Handling"> below. 215*0Sstevel@tonic-gateOtherwise, only L<built-in attributes|"Built-in Attributes"> will be returned. 216*0Sstevel@tonic-gate 217*0Sstevel@tonic-gate=item reftype 218*0Sstevel@tonic-gate 219*0Sstevel@tonic-gateThis routine expects a single parameter--a reference to a subroutine or 220*0Sstevel@tonic-gatevariable. It returns the built-in type of the referenced variable, 221*0Sstevel@tonic-gateignoring any package into which it might have been blessed. 222*0Sstevel@tonic-gateThis can be useful for determining the I<type> value which forms part of 223*0Sstevel@tonic-gatethe method names described in L<"Package-specific Attribute Handling"> below. 224*0Sstevel@tonic-gate 225*0Sstevel@tonic-gate=back 226*0Sstevel@tonic-gate 227*0Sstevel@tonic-gateNote that these routines are I<not> exported by default. 228*0Sstevel@tonic-gate 229*0Sstevel@tonic-gate=head2 Package-specific Attribute Handling 230*0Sstevel@tonic-gate 231*0Sstevel@tonic-gateB<WARNING>: the mechanisms described here are still experimental. Do not 232*0Sstevel@tonic-gaterely on the current implementation. In particular, there is no provision 233*0Sstevel@tonic-gatefor applying package attributes to 'cloned' copies of subroutines used as 234*0Sstevel@tonic-gateclosures. (See L<perlref/"Making References"> for information on closures.) 235*0Sstevel@tonic-gatePackage-specific attribute handling may change incompatibly in a future 236*0Sstevel@tonic-gaterelease. 237*0Sstevel@tonic-gate 238*0Sstevel@tonic-gateWhen an attribute list is present in a declaration, a check is made to see 239*0Sstevel@tonic-gatewhether an attribute 'modify' handler is present in the appropriate package 240*0Sstevel@tonic-gate(or its @ISA inheritance tree). Similarly, when C<attributes::get> is 241*0Sstevel@tonic-gatecalled on a valid reference, a check is made for an appropriate attribute 242*0Sstevel@tonic-gate'fetch' handler. See L<"EXAMPLES"> to see how the "appropriate package" 243*0Sstevel@tonic-gatedetermination works. 244*0Sstevel@tonic-gate 245*0Sstevel@tonic-gateThe handler names are based on the underlying type of the variable being 246*0Sstevel@tonic-gatedeclared or of the reference passed. Because these attributes are 247*0Sstevel@tonic-gateassociated with subroutine or variable declarations, this deliberately 248*0Sstevel@tonic-gateignores any possibility of being blessed into some package. Thus, a 249*0Sstevel@tonic-gatesubroutine declaration uses "CODE" as its I<type>, and even a blessed 250*0Sstevel@tonic-gatehash reference uses "HASH" as its I<type>. 251*0Sstevel@tonic-gate 252*0Sstevel@tonic-gateThe class methods invoked for modifying and fetching are these: 253*0Sstevel@tonic-gate 254*0Sstevel@tonic-gate=over 4 255*0Sstevel@tonic-gate 256*0Sstevel@tonic-gate=item FETCH_I<type>_ATTRIBUTES 257*0Sstevel@tonic-gate 258*0Sstevel@tonic-gateThis method receives a single argument, which is a reference to the 259*0Sstevel@tonic-gatevariable or subroutine for which package-defined attributes are desired. 260*0Sstevel@tonic-gateThe expected return value is a list of associated attributes. 261*0Sstevel@tonic-gateThis list may be empty. 262*0Sstevel@tonic-gate 263*0Sstevel@tonic-gate=item MODIFY_I<type>_ATTRIBUTES 264*0Sstevel@tonic-gate 265*0Sstevel@tonic-gateThis method is called with two fixed arguments, followed by the list of 266*0Sstevel@tonic-gateattributes from the relevant declaration. The two fixed arguments are 267*0Sstevel@tonic-gatethe relevant package name and a reference to the declared subroutine or 268*0Sstevel@tonic-gatevariable. The expected return value is a list of attributes which were 269*0Sstevel@tonic-gatenot recognized by this handler. Note that this allows for a derived class 270*0Sstevel@tonic-gateto delegate a call to its base class, and then only examine the attributes 271*0Sstevel@tonic-gatewhich the base class didn't already handle for it. 272*0Sstevel@tonic-gate 273*0Sstevel@tonic-gateThe call to this method is currently made I<during> the processing of the 274*0Sstevel@tonic-gatedeclaration. In particular, this means that a subroutine reference will 275*0Sstevel@tonic-gateprobably be for an undefined subroutine, even if this declaration is 276*0Sstevel@tonic-gateactually part of the definition. 277*0Sstevel@tonic-gate 278*0Sstevel@tonic-gate=back 279*0Sstevel@tonic-gate 280*0Sstevel@tonic-gateCalling C<attributes::get()> from within the scope of a null package 281*0Sstevel@tonic-gatedeclaration C<package ;> for an unblessed variable reference will 282*0Sstevel@tonic-gatenot provide any starting package name for the 'fetch' method lookup. 283*0Sstevel@tonic-gateThus, this circumstance will not result in a method call for package-defined 284*0Sstevel@tonic-gateattributes. A named subroutine knows to which symbol table entry it belongs 285*0Sstevel@tonic-gate(or originally belonged), and it will use the corresponding package. 286*0Sstevel@tonic-gateAn anonymous subroutine knows the package name into which it was compiled 287*0Sstevel@tonic-gate(unless it was also compiled with a null package declaration), and so it 288*0Sstevel@tonic-gatewill use that package name. 289*0Sstevel@tonic-gate 290*0Sstevel@tonic-gate=head2 Syntax of Attribute Lists 291*0Sstevel@tonic-gate 292*0Sstevel@tonic-gateAn attribute list is a sequence of attribute specifications, separated by 293*0Sstevel@tonic-gatewhitespace or a colon (with optional whitespace). 294*0Sstevel@tonic-gateEach attribute specification is a simple 295*0Sstevel@tonic-gatename, optionally followed by a parenthesised parameter list. 296*0Sstevel@tonic-gateIf such a parameter list is present, it is scanned past as for the rules 297*0Sstevel@tonic-gatefor the C<q()> operator. (See L<perlop/"Quote and Quote-like Operators">.) 298*0Sstevel@tonic-gateThe parameter list is passed as it was found, however, and not as per C<q()>. 299*0Sstevel@tonic-gate 300*0Sstevel@tonic-gateSome examples of syntactically valid attribute lists: 301*0Sstevel@tonic-gate 302*0Sstevel@tonic-gate switch(10,foo(7,3)) : expensive 303*0Sstevel@tonic-gate Ugly('\(") :Bad 304*0Sstevel@tonic-gate _5x5 305*0Sstevel@tonic-gate locked method 306*0Sstevel@tonic-gate 307*0Sstevel@tonic-gateSome examples of syntactically invalid attribute lists (with annotation): 308*0Sstevel@tonic-gate 309*0Sstevel@tonic-gate switch(10,foo() # ()-string not balanced 310*0Sstevel@tonic-gate Ugly('(') # ()-string not balanced 311*0Sstevel@tonic-gate 5x5 # "5x5" not a valid identifier 312*0Sstevel@tonic-gate Y2::north # "Y2::north" not a simple identifier 313*0Sstevel@tonic-gate foo + bar # "+" neither a colon nor whitespace 314*0Sstevel@tonic-gate 315*0Sstevel@tonic-gate=head1 EXPORTS 316*0Sstevel@tonic-gate 317*0Sstevel@tonic-gate=head2 Default exports 318*0Sstevel@tonic-gate 319*0Sstevel@tonic-gateNone. 320*0Sstevel@tonic-gate 321*0Sstevel@tonic-gate=head2 Available exports 322*0Sstevel@tonic-gate 323*0Sstevel@tonic-gateThe routines C<get> and C<reftype> are exportable. 324*0Sstevel@tonic-gate 325*0Sstevel@tonic-gate=head2 Export tags defined 326*0Sstevel@tonic-gate 327*0Sstevel@tonic-gateThe C<:ALL> tag will get all of the above exports. 328*0Sstevel@tonic-gate 329*0Sstevel@tonic-gate=head1 EXAMPLES 330*0Sstevel@tonic-gate 331*0Sstevel@tonic-gateHere are some samples of syntactically valid declarations, with annotation 332*0Sstevel@tonic-gateas to how they resolve internally into C<use attributes> invocations by 333*0Sstevel@tonic-gateperl. These examples are primarily useful to see how the "appropriate 334*0Sstevel@tonic-gatepackage" is found for the possible method lookups for package-defined 335*0Sstevel@tonic-gateattributes. 336*0Sstevel@tonic-gate 337*0Sstevel@tonic-gate=over 4 338*0Sstevel@tonic-gate 339*0Sstevel@tonic-gate=item 1. 340*0Sstevel@tonic-gate 341*0Sstevel@tonic-gateCode: 342*0Sstevel@tonic-gate 343*0Sstevel@tonic-gate package Canine; 344*0Sstevel@tonic-gate package Dog; 345*0Sstevel@tonic-gate my Canine $spot : Watchful ; 346*0Sstevel@tonic-gate 347*0Sstevel@tonic-gateEffect: 348*0Sstevel@tonic-gate 349*0Sstevel@tonic-gate use attributes (); 350*0Sstevel@tonic-gate attributes::->import(Canine => \$spot, "Watchful"); 351*0Sstevel@tonic-gate 352*0Sstevel@tonic-gate=item 2. 353*0Sstevel@tonic-gate 354*0Sstevel@tonic-gateCode: 355*0Sstevel@tonic-gate 356*0Sstevel@tonic-gate package Felis; 357*0Sstevel@tonic-gate my $cat : Nervous; 358*0Sstevel@tonic-gate 359*0Sstevel@tonic-gateEffect: 360*0Sstevel@tonic-gate 361*0Sstevel@tonic-gate use attributes (); 362*0Sstevel@tonic-gate attributes::->import(Felis => \$cat, "Nervous"); 363*0Sstevel@tonic-gate 364*0Sstevel@tonic-gate=item 3. 365*0Sstevel@tonic-gate 366*0Sstevel@tonic-gateCode: 367*0Sstevel@tonic-gate 368*0Sstevel@tonic-gate package X; 369*0Sstevel@tonic-gate sub foo : locked ; 370*0Sstevel@tonic-gate 371*0Sstevel@tonic-gateEffect: 372*0Sstevel@tonic-gate 373*0Sstevel@tonic-gate use attributes X => \&foo, "locked"; 374*0Sstevel@tonic-gate 375*0Sstevel@tonic-gate=item 4. 376*0Sstevel@tonic-gate 377*0Sstevel@tonic-gateCode: 378*0Sstevel@tonic-gate 379*0Sstevel@tonic-gate package X; 380*0Sstevel@tonic-gate sub Y::x : locked { 1 } 381*0Sstevel@tonic-gate 382*0Sstevel@tonic-gateEffect: 383*0Sstevel@tonic-gate 384*0Sstevel@tonic-gate use attributes Y => \&Y::x, "locked"; 385*0Sstevel@tonic-gate 386*0Sstevel@tonic-gate=item 5. 387*0Sstevel@tonic-gate 388*0Sstevel@tonic-gateCode: 389*0Sstevel@tonic-gate 390*0Sstevel@tonic-gate package X; 391*0Sstevel@tonic-gate sub foo { 1 } 392*0Sstevel@tonic-gate 393*0Sstevel@tonic-gate package Y; 394*0Sstevel@tonic-gate BEGIN { *bar = \&X::foo; } 395*0Sstevel@tonic-gate 396*0Sstevel@tonic-gate package Z; 397*0Sstevel@tonic-gate sub Y::bar : locked ; 398*0Sstevel@tonic-gate 399*0Sstevel@tonic-gateEffect: 400*0Sstevel@tonic-gate 401*0Sstevel@tonic-gate use attributes X => \&X::foo, "locked"; 402*0Sstevel@tonic-gate 403*0Sstevel@tonic-gate=back 404*0Sstevel@tonic-gate 405*0Sstevel@tonic-gateThis last example is purely for purposes of completeness. You should not 406*0Sstevel@tonic-gatebe trying to mess with the attributes of something in a package that's 407*0Sstevel@tonic-gatenot your own. 408*0Sstevel@tonic-gate 409*0Sstevel@tonic-gate=head1 SEE ALSO 410*0Sstevel@tonic-gate 411*0Sstevel@tonic-gateL<perlsub/"Private Variables via my()"> and 412*0Sstevel@tonic-gateL<perlsub/"Subroutine Attributes"> for details on the basic declarations; 413*0Sstevel@tonic-gateL<attrs> for the obsolescent form of subroutine attribute specification 414*0Sstevel@tonic-gatewhich this module replaces; 415*0Sstevel@tonic-gateL<perlfunc/use> for details on the normal invocation mechanism. 416*0Sstevel@tonic-gate 417*0Sstevel@tonic-gate=cut 418*0Sstevel@tonic-gate 419