class Attribute

Member variable

class Attribute { }

In Perl 6 lingo, an attribute refers to a per-instance/object storage slot. An Attribute is used to talk about classes' and roles' attributes on the meta level.

Normal usage of attributes does not require the user to use class Attribute explicitly.

The usual way to obtain an object of type Attribute is by introspection:

class Useless {
    has @!things;
}
my $a = Useless.^attributes(:local)[0];
say $a.perl;            # 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 meta class, all is fair game

my $instance = Useless.new;
$a.set_value($instance, [123]);
say $a.get_value($instance);        # OUTPUT: «[1 2 3]␤» 

Traits

Trait is default

An attribute that is assigned Nil will revert to its default value set with the trait is default.

class C {
    has $.a is default(42is rw = 666
}
my $c = C.new;
say $c;
$c.a = Nil;
say $c;
# OUTPUT: «C.new(a => 666)␤C.new(a => 42)␤» 

Trait is 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.

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.␤» 

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:

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.␤» 

trait is DEPRECATED

multi sub trait_mod:<is>(Attribute:D $r:$DEPRECATED!)

Marks an attribute as deprecated, optionally with a message what to use instead.

class C {
    has $.foo is DEPRECATED("'bar'");
}
my $c = C.newfoo => 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:

# Saw 1 occurrence of deprecated code. 
# ===================================== 
# Method foo (from C) seen at: 
# script.pl6, line 5 
# Please use 'bar' instead. 

Methods

method name

Defined as:

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.

class Foo {
    has @!bar;
}
my $a = Foo.^attributes(:local)[0];
say $a.name;            # OUTPUT: «@!bar␤» 

method package

Defined as:

method package(Attribute:D: --> Mu:U)

Returns the package (class/grammar/role) to which this attribute belongs.

class Boo {
    has @!baz;
}
my $a = Boo.^attributes(:local)[0];
say $a.package;         # OUTPUT: «(Boo)␤» 

method has_accessor

Defined as:

method has_accessor(Attribute:D: --> Bool:D)

Returns True if the attribute has a public accessor method.

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 readonly

Defined as:

method readonly(Attribute:D: --> Bool:D)

Returns True for readonly attributes, which is the default, or False for attributes marked as is rw.

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 type

Defined as:

method type(Attribute:D: --> Mu)

Returns the type constraint of the attribute.

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

Defined as:

method get_value(Attribute:D: Mu $instance)

Returns the value stored in this attribute of object $instance.

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

Defined as:

method set_value(Attribute:D: Mu $instanceMu \new_val)

Binds the value new_val to this attribute of object $instance.

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($a42);
$a.speak# OUTPUT: «42␤» 

Note that this method violates encapsulation of the object, and should be used with care. Here be dragons.

trait is required

multi sub trait_mod:<is> (Attribute $attr:$required!)

Marks an attribute as being required. If a value is not provided during object construction, an exception is thrown.

class Foo {
   has $.bar is required;
   has $.baz;
};
 
Foo.new(bar => 42); # works 
Foo.new(baz => 42);
CATCH { default { put .^name''.Str } };
# OUTPUT: «X::Attribute::Required: The attribute '$!bar' is required, 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.

trait is rw

multi sub 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.

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␤» 

Type Graph

Type relations for Attribute
perl6-type-graph Attribute Attribute Any Any Attribute->Any Mu Mu Any->Mu

Expand above chart