txt: ## attribute.md
  class Attribute
  
  Member variable
  
  ```raku
  class Attribute { }
  ```
  
  In Raku lingo, an *attribute* refers to a per-instance/object storage slot. An `Attribute` is used to talk about classes' and roles' attributes at the metalevel.
  
  Normal usage of attributes does not require the user to use this class explicitly.
  
  # [Traits](#class_Attribute "go to top of document")[§](#Traits "direct link")
  
  ## [Trait is default](#class_Attribute "go to top of document")[§](#Trait_is_default "direct link")
  
  An attribute that is assigned [`Nil`](/type/Nil) will revert to its default value set with the trait `is default`. In the case of arrays or associatives, the argument of `is default` will set the default item value or hash value.
  
  ```raku
  class C {
      has $.a is default(42) is rw = 666
  }
  my $c = C.new;
  say $c;
  $c.a = Nil;
  say $c;
  # OUTPUT: «C.new(a => 666)␤C.new(a => 42)␤»
  class Foo {
      has @.bar is default(42) is rw
  };
  my $foo = Foo.new( bar => <a b c> );
  $foo.bar =Nil;
  say $foo; # OUTPUT: «Foo.new(bar => [42])␤»
  ```
  
  ## [Trait is required](#class_Attribute "go to top of document")[§](#Trait_is_required "direct link")
  
  ```raku
  multi trait_mod:<is> (Attribute $attr, :$required!)
  ```
  
  The trait `is required` will mark the attribute as to be filled with a value when the object is instantiated. Failing to do so will result in a runtime error.
  
  ```raku
  class C {
      has $.a is required
  }
  my $c = C.new;
  CATCH{ default { say .^name, ': ', .Str } }
  # OUTPUT: «X::Attribute::Required: The attribute '$!a' is required, but you did not provide a value for it.␤»
  ```
  
  This trait also allows attributes to be typed with types that have a `:D` smiley without giving them a default value:
  
  ```raku
  class Power {
      has Numeric:D $.base     is required;
      has Numeric:D $.exponent is required;
      multi method Numeric(::?CLASS:D: --> Numeric:D) {
          $!base ** $!exponent
      }
  }
  ```
  
  **Available as of 6.d language version** (early implementation exists in Rakudo compiler 2018.08+): You can specify a reason why the attribute is required:
  
  ```raku
  class D {
      has $.a is required("it is a good idea");
  }
  my $d = D.new;
  CATCH{ default { say .^name, ': ', .Str } }
  # OUTPUT: «X::Attribute::Required: The attribute '$!a' is required because it is a good idea,␤but you did not provide a value for it.␤»
  
  ```
  
  `is required` doesn't just affect the default constructor, it checks for the attribute at a lower level, so it will work for custom constructors written using [bless](/routine/bless).
  
  ## [trait is DEPRECATED](#class_Attribute "go to top of document")[§](#trait_is_DEPRECATED "direct link")
  
  ```raku
  multi trait_mod:<is>(Attribute:D $r, :$DEPRECATED!)
  ```
  
  Marks an attribute as deprecated, optionally with a message what to use instead.
  
  ```raku
  class C {
      has $.foo is DEPRECATED("'bar'");
  }
  my $c = C.new( foo => 42 );  # doesn't trigger with initialization (yet)
  say $c.foo;                  # does trigger on usage
  ```
  
  **After** the program is finished, this will show something like this on STDERR:
  
  ```raku
  # Saw 1 occurrence of deprecated code.
  # =====================================
  # Method foo (from C) seen at:
  # script.raku, line 5
  # Please use 'bar' instead.
  ```
  
  ## [trait is rw](#class_Attribute "go to top of document")[§](#trait_is_rw "direct link")
  
  ```raku
  multi trait_mod:<is> (Attribute:D $attr, :$rw!)
  ```
  
  Marks an attribute as read/write as opposed to the default `readonly`. The default accessor for the attribute will return a writable value.
  
  ```raku
  class Boo {
     has $.bar is rw;
     has $.baz;
  };
  
  my $boo = Boo.new;
  $boo.bar = 42; # works
  $boo.baz = 42;
  CATCH { default { put .^name, ': ', .Str } };
  # OUTPUT: «X::Assignment::RO: Cannot modify an immutable Any␤»
  ```
  
  ## [trait is built](#class_Attribute "go to top of document")[§](#trait_is_built "direct link")
  
  ```raku
  multi trait_mod:<is>(Attribute:D $a, :$built!)
  ```
  
  By default, this trait allows setting up a *private attribute* during object construction via `.new`. The same trait can be used to prevent setting up a *public attribute* via `.new` by passing it the Boolean value `False`.
  
  ```raku
  class Foo {
      has $!bar is built; # same as `is built(True)`
      has $.baz is built(False);
  
      method bar {
          $!bar
      }
  }
  
  my $foo = Foo.new(bar => 1, baz => 2);
  say $foo.bar; # OUTPUT: «1␤»
  say $foo.baz; # OUTPUT: «Any␤»
  ```
  
  The `built` trait also allows named arguments to be specified. Currently the `:bind` named argument can be specified. In that case, any (default) value will be **bound** to the attribute, rather than assigned. This allows for specifying a `Proxy` to an attribute:
  
  ```raku
  class Foo {
      has $!foo is built(:bind) = Proxy.new: :STORE{...}, :FETCH{...}
  }
  ```
  
  Available as of the 2020.01 release of the Rakudo compiler.
  
  # [Methods](#class_Attribute "go to top of document")[§](#Methods "direct link")
  
  The usual way to obtain an object of type `Attribute` is by introspection:
  
  ```raku
  class Useless {
      has @!things;
  }
  my $a = Useless.^attributes(:local)[0];
  say $a.raku;            # OUTPUT: «Attribute.new␤»
  say $a.name;            # OUTPUT: «@!things␤»
  say $a.package;         # OUTPUT: «(Useless)␤»
  say $a.has_accessor;    # OUTPUT: «False␤»
  ```
  
  Modifying a private attribute from the outside is usually not possible, but since Attribute is at the level of the metaclass, all is fair game.
  
  ## [method name](#class_Attribute "go to top of document")[§](#method_name "direct link")
  
  ```raku
  method name(Attribute:D: --> Str:D)
  ```
  
  Returns the name of the attribute. Note that this is always the private name, so if an attribute is declared as `has $.a`, the name returned is `$!a`.
  
  ```raku
  class Foo {
      has @!bar;
  }
  my $a = Foo.^attributes(:local)[0];
  say $a.name;            # OUTPUT: «@!bar␤»
  ```
  
  ## [method package](#class_Attribute "go to top of document")[§](#method_package "direct link")
  
  ```raku
  method package()
  ```
  
  Returns the package (class/grammar/role) to which this attribute belongs.
  
  ```raku
  class Boo {
      has @!baz;
  }
  my $a = Boo.^attributes(:local)[0];
  say $a.package;         # OUTPUT: «(Boo)␤»
  ```
  
  ## [method has\_accessor](#class_Attribute "go to top of document")[§](#method_has_accessor "direct link")
  
  ```raku
  method has_accessor(Attribute:D: --> Bool:D)
  ```
  
  Returns `True` if the attribute has a public accessor method.
  
  ```raku
  class Container {
      has $!private;
      has $.public;
  }
  my $private = Container.^attributes(:local)[0];
  my $public = Container.^attributes(:local)[1];
  say $private.has_accessor; # OUTPUT: «False␤»
  say $public.has_accessor;  # OUTPUT: «True␤»
  ```
  
  ## [method rw](#class_Attribute "go to top of document")[§](#method_rw "direct link")
  
  ```raku
  method rw(Attribute:D: --> Bool:D)
  ```
  
  Returns `True` for attributes that have the "is rw" trait applied to them.
  
  ```raku
  class Library {
      has $.address; # Read-only value
      has @.new-books is rw;
  }
  my $addr = Library.^attributes(:local)[0];
  my $new-books = Library.^attributes(:local)[1];
  say $addr.rw;      # OUTPUT: «False␤»
  say $new-books.rw; # OUTPUT: «True␤»
  ```
  
  ## [method readonly](#class_Attribute "go to top of document")[§](#method_readonly "direct link")
  
  ```raku
  method readonly(Attribute:D: --> Bool:D)
  ```
  
  Returns `True` for readonly attributes, which is the default, or `False` for attributes marked as `is rw`.
  
  ```raku
  class Library {
      has $.address; # Read-only value
      has @.new-books is rw;
  }
  my $addr = Library.^attributes(:local)[0];
  my $new-books = Library.^attributes(:local)[1];
  say $addr.readonly;      # OUTPUT: «True␤»
  say $new-books.readonly; # OUTPUT: «False␤»
  ```
  
  ## [method required](#class_Attribute "go to top of document")[§](#method_required "direct link")
  
  ```raku
  method required(Attribute:D: --> Any:D)
  ```
  
  Returns `1` for attributes that have the "is required" trait applied, or [`Mu`](/type/Mu) if the attribute did not have that trait applied. If the "is required" trait is applied with a string, then that string will be returned instead of `1`.
  
  ```raku
  class Library {
      has $.address is required;
      has @.new-books is required("we always need more books");
  }
  my $addr = Library.^attributes(:local)[0];
  my $new-books = Library.^attributes(:local)[1];
  say $addr.required;      # OUTPUT: «1␤»
  say $new-books.readonly; # OUTPUT: «"we always need more books"␤»
  ```
  
  ## [method type](#class_Attribute "go to top of document")[§](#method_type "direct link")
  
  ```raku
  method type(Attribute:D: --> Mu)
  ```
  
  Returns the type constraint of the attribute.
  
  ```raku
  class TypeHouse {
      has Int @.array;
      has $!scalar;
      has @.mystery;
  }
  my @types = TypeHouse.^attributes(:local)[0..2];
  for 0..2 { say @types[$_].type }
  # OUTPUT: «(Positional[Int])
  # (Mu)
  # (Positional)␤»
  ```
  
  ## [method get\_value](#class_Attribute "go to top of document")[§](#method_get_value "direct link")
  
  ```raku
  method get_value(Mu $obj)
  ```
  
  Returns the value stored in this attribute of object `$obj`.
  
  ```raku
  class Violated {
      has $!private-thing = 5;
  }
  my $private = Violated.^attributes(:local)[0];
  say $private.get_value(Violated.new); # OUTPUT: «5␤»
  ```
  
  Note that this method violates encapsulation of the object, and should be used with care. Here be dragons.
  
  ## [method set\_value](#class_Attribute "go to top of document")[§](#method_set_value "direct link")
  
  ```raku
  method set_value(Mu $obj, Mu \new_val)
  ```
  
  Binds the value `new_val` to this attribute of object `$obj`.
  
  ```raku
  class A {
      has $!a = 5;
      method speak() { say $!a; }
  }
  my $attr = A.^attributes(:local)[0];
  my $a = A.new;
  $a.speak; # OUTPUT: «5␤»
  $attr.set_value($a, 42);
  $a.speak; # OUTPUT: «42␤»
  ```
  
  Note that this method violates encapsulation of the object, and should be used with care. Here be dragons.
  
  ## [method gist](#class_Attribute "go to top of document")[§](#method_gist "direct link")
  
  ```raku
  multi method gist(Attribute:D:)
  ```
  
  Returns the name of the type followed by the name of the attribute.
  
  ```raku
  class Hero {
      has @!inventory;
      has Str $.name;
      submethod BUILD( :$name, :@inventory ) {
          $!name = $name;
          @!inventory = @inventory
      }
  }
  say Hero.^attributes(:local)[0]; # OUTPUT: «Positional @!inventory␤»
  
  ```
  
  Since say implicitly calls `.gist`, that is what produces the output here.
  
  # [Optional introspection](#class_Attribute "go to top of document")[§](#Optional_introspection "direct link")
  
  ## [DEPRECATED](#class_Attribute "go to top of document")[§](#DEPRECATED "direct link")
  
  If an attribute is marked as `DEPRECATED`, then calling the `DEPRECATED` method is possible and will return `"something else"` (if no specific reason was specified) or the string that was specified with the `DEPRECATED` trait.
  
  If an attribute is **not** marked as DEPRECATED, one **cannot** call the `DEPRECATED` method. Therefore, the `.?method` syntax should be used.
  
  ```raku
  class Hangout {
      has $.table;
      has $.bar is DEPRECATED("the patio");
  }
  my $attr-table = Hangout.^attributes(:local)[0];
  my $attr-bar = Hangout.^attributes(:local)[1];
  with $attr-table.?DEPRECATED -> $text {     # does not trigger
      say "Table is deprecated with '$text'";
      # OUTPUT:
  }
  with $attr-bar.?DEPRECATED -> $text {
      say "Bar is deprecated with '$text'";
      # OUTPUT: «Bar is deprecated with 'the patio'"␤»
  }
  ```
  
  # [Typegraph](# "go to top of document")[§](#typegraphrelations "direct link")
  
  Type relations for `Attribute`
  
  
  
  raku-type-graph
  
  
  
  Attribute
  Attribute
  
  
  Any
  Any
  
  
  Attribute->Any
  
  
  
  Mu
  Mu
  
  
  Any->Mu
  
  [Expand chart above](/assets/typegraphs/Attribute.svg)
  