# Attributes A sub attribute is a colon-prefixed annotation between the sub’s name (or signature) and its body. Attributes mark a sub as having some special property — being a method, being an lvalue, having a prototype, being constant, being subject to some third-party mechanism — that the runtime, the parser, or a user-written attribute handler can act on. ```perl sub greet :method ($name) { ... } sub editable :lvalue { ... } sub mypush :prototype(\@@) { ... } sub PI :const { 3.14159 } sub handler :Memoize { ... } # third-party attribute ``` ## The four attribute steps To follow how an attribute affects a sub, distinguish four phases: 1. **Parse.** The compiler reads `:foo(args)` and breaks it into a name (`foo`) and an optional parameter string (`args`). 2. **Register.** The compiler invokes either a built-in handler (for `:lvalue`, `:method`, `:prototype(...)`) or `MODIFY_CODE_ATTRIBUTES` from the relevant package (for user-defined attributes). 3. **Store.** Built-in attributes set a flag on the CV (the compiled sub object). User attributes are stored wherever the handler chooses. 4. **Query.** Anyone can later ask `attributes::get(\&sub)` for the attribute list. Built-in attributes are also queryable through more direct APIs (`prototype`, `is_lvalue`, …). The four phases are why attributes are heterogeneous in behaviour: built-in attributes are runtime concepts; user attributes are whatever code in `MODIFY_CODE_ATTRIBUTES` decides to do with them. ## Built-in attributes ### `:lvalue` Marks the sub as usable on the left-hand side of an assignment. The body’s last expression must be an lvalue. See [lvalue and context](lvalue-and-context.md). ```perl sub editable :lvalue { $self->{x} } $obj->editable = 42; # writes through to $self->{x} ``` ### `:method` Hint to the parser and to introspection that this sub is meant to be called as a method. The flag is mostly informational; it also suppresses prototype effects (since methods don’t honour prototypes anyway): ```perl package Counter; sub increment :method { my $self = shift; $self->{n}++; } ``` `:method` does **not** automatically `use parent` or set `@ISA`; it does not change dispatch. It is a documentation / intent marker that the runtime also uses to skip prototype processing. ### `:prototype(...)` The attribute form of a [prototype](prototypes.md), required when [signatures](signatures.md) are enabled in the same scope: ```perl use feature 'signatures'; sub mygrep :prototype(&@) ($code, @list) { grep { $code->($_) } @list; } ``` The body’s parameter list is the signature; the attribute carries the prototype. Without the attribute form, the parser cannot tell which parenthesised list is which. ### `:const` Promises the runtime that the sub’s body produces a constant result, enabling more aggressive inlining than the bare `()` prototype gives: ```perl sub PI :const { 3.14159265358979 } ``` `:const` was introduced for use by `use constant` and similar tools. Most code should reach for `use constant` rather than applying `:const` directly. ## Third-party attributes Any package can register attribute handlers for code refs by implementing `MODIFY_CODE_ATTRIBUTES`. The classic example is `Attribute::Handlers`, which provides a more declarative API on top of the raw mechanism. A user attribute looks identical to a built-in at the call site: ```perl use Some::Memoize; # provides ':Memoize' attribute sub expensive :Memoize { ... } ``` The package providing the attribute decides what `:Memoize` means. Common third-party attributes: - `:Memoize` — automatically cache return values (from `Memoize`). - `:Logged` — wrap the sub with logging entry/exit (from various AOP-style modules). - `:Test`, `:Benchmark` — testing-framework markers. When you see a colon-attribute that isn’t on the built-in list above, find the package supplying it. ## How attributes are written Several attributes can be chained. The ordering on disk is the ordering they’re processed in: ```perl sub fancy :method :prototype(\@) :Memoize { ... } ``` Attributes attach to *both* a forward declaration and the definition; if you write both, the attribute lists must agree: ```perl sub greet :method; # forward declaration with :method sub greet :method ($name) { # body, same attribute ... } ``` A signature, when present, comes after attributes: ```perl sub greet :method ($name) { # OK ... } sub greet ($name) :method { # error: attributes must precede signature ... } ``` ## What attributes do *not* do - They are not type annotations. `:Int` is not a built-in; attempts to read it that way will silently do nothing unless some package has registered a handler that means the same thing. - They are not metadata for the test framework unless the test framework registered a handler for them. Sprinkling `:tested` on subs does nothing without code on the other side reading the annotation. - They are not optimisation directives. `:fast` does nothing. ## Querying a sub’s attributes ```perl use attributes; sub demo :method :prototype($) :Memoize { ... } my @attrs = attributes::get(\&demo); # returns: ('method', 'prototype($)', 'Memoize') ``` This is the introspection equivalent of [`prototype`](../perlfunc/prototype.md) — it answers «what annotations does this sub carry?» rather than «what does this sub look like to the parser?». ## See also - [Declaration](declaration.md) — where the `:attr` syntax fits in the declaration grammar. - [Prototypes](prototypes.md) — `:prototype(...)` is one attribute among several. - [Lvalue and context](lvalue-and-context.md) — the meaning of `:lvalue`. - [`prototype`](../perlfunc/prototype.md) — runtime introspection of one specific built-in attribute. - [Object-Oriented Programming](../../../guide/oop/index.md) — `:method` and the broader OO context.