-
Notifications
You must be signed in to change notification settings - Fork 290
Revise and add to Attribute's documentation #3441
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Open
Kaiepi
wants to merge
4
commits into
Raku:main
Choose a base branch
from
Kaiepi:attribute-new
base: main
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Open
Changes from all commits
Commits
Show all changes
4 commits
Select commit
Hold shift + click to select a range
e1ad867
Document how to create attributes and revise Attribute's type page
Kaiepi ede882c
Document binding using the "is built" trait
Kaiepi 2ca3dce
Remove some unnecessary :solos in the Attribute type page
Kaiepi c0d302d
Elaborate on the attributes metamethod in the Attribute type page
Kaiepi File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -10,8 +10,44 @@ In Raku lingo, an I<attribute> refers to a per-instance/object storage slot. | |
An C<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. | ||
C<Attribute> is typically useful when working with the L<MOP|/language/mop>. | ||
For instance, the attributes of any type that supports them can be | ||
introspected using the C<attributes> metamethod, which returns a list of | ||
C<Attribute> instances. Using these, we can inspect various properties of | ||
a type's attributes, such as their names: | ||
|
||
=begin code | ||
class WithAttributes { | ||
has $.attribute; | ||
has $.attribute-two-electric-boogaloo; | ||
has $.yet-another-attribute; | ||
} | ||
|
||
.say for WithAttributes.^attributes(:local).map(*.name); | ||
# OUTPUT: | ||
# $!attribute | ||
# $!attribute-two-electric-boogaloo | ||
# $!yet-another-attribute | ||
=end code | ||
|
||
Because of C<Attribute>, a type containing attributes, such as this: | ||
|
||
=for code | ||
class WithAttribute { | ||
has $.attribute; | ||
} | ||
|
||
Is not something only the compiler knows how to generate. This class in | ||
particular can be generated manually like so: | ||
|
||
=for code :solo | ||
BEGIN { | ||
constant WithAttribute = Metamodel::ClassHOW.new_type: :name<WithAttribute>; | ||
WithAttribute.^add_attribute: Attribute.new: | ||
:name<$!attribute>, :type(Any), :package(WithAttribute), | ||
:1has_accessor; | ||
WithAttribute.^compose; | ||
} | ||
|
||
=head1 Traits | ||
|
||
|
@@ -39,8 +75,6 @@ argument of C<is default> will set the default item value or hash value. | |
|
||
=head2 X<Trait is required|trait,is required (Attribute)> | ||
|
||
Defined as: | ||
|
||
multi sub trait_mod:<is> (Attribute $attr, :$required!) | ||
|
||
The trait C<is required> will mark the attribute as to be filled with a value | ||
|
@@ -104,8 +138,6 @@ STDERR: | |
|
||
=head2 X<trait is rw|trait,is rw (Attribute)> | ||
|
||
Defined as: | ||
|
||
multi sub trait_mod:<is> (Attribute:D $attr, :$rw!) | ||
|
||
Marks an attribute as read/write as opposed to the default C<readonly>. The | ||
|
@@ -124,47 +156,72 @@ default accessor for the attribute will return a writable value. | |
|
||
=head2 X<trait is built|trait,is built (Attribute)> | ||
|
||
Defined as: | ||
|
||
multi sub trait_mod:<is>(Attribute:D $a, :$built!) | ||
coke marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
||
By default, this trait allows setting up a I«private attribute» during object | ||
construction via C«.new». The same trait can be used to prevent setting up a | ||
I«public attribute» via C«.new» by passing it the boolean value C«False». | ||
By default, this trait allows setting up a I«private attribute» during | ||
object construction via C«.new». The same trait can be used to prevent | ||
setting up a I«public attribute» via C«.new» by passing it the boolean | ||
value C«False». Setting up an attribute with its value is ordinarily | ||
handled by assigning the value, but if C<:bind> is passed, then it will | ||
be bound instead: | ||
|
||
class Foo { | ||
has $!bar is built; # same as `is built(True)` | ||
has $.baz is built(False); | ||
has $!qux is built(:bind); | ||
|
||
method bar { | ||
$!bar | ||
} | ||
method bar(::?CLASS:D:) { $!bar } | ||
method qux(::?CLASS:D:) { $!qux } | ||
} | ||
|
||
my $foo = Foo.new(bar => 1, baz => 2); | ||
say $foo.bar; # «1» | ||
say $foo.baz; # «Any» | ||
my Foo:D $foo .= new: :bar[], :baz[], :qux[]; | ||
say $foo.bar.raku; # OUTPUT: «$[]» | ||
say $foo.baz.raku; # OUTPUT: «Any» | ||
say $foo.qux.raku; # OUTPUT: «[]» | ||
|
||
=head1 Methods | ||
|
||
The usual way to obtain an object of type C<Attribute> is by introspection: | ||
|
||
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. | ||
=head2 method new | ||
|
||
=for code :skip-test<too long a method signature for one line> | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. In principle, there should be no problem with so many lines, as long as you use =for code or =begin code |
||
method new(Attribute:_: | ||
:$name!, :$type!, :$package!, | ||
:$inlined = 0, :$has_accessor = 0, :$is_built = $has_accessor, :$is_bound = 0, | ||
:$positional_delegate = 0, :$associative_delegate = 0, *%other) | ||
|
||
Creates a new attribute. The following named arguments are required: | ||
|
||
- C<$name> contains the attribute's name, which should always be a | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Maybe use =item here? |
||
string prefixed with the attribute's sigil and the I<!> twigil. | ||
- C<$type> contains type of the attribute. When creating untyped | ||
attributes, C<Any> should be passed. | ||
- C<$package> contains the type to which the attribute belongs to. | ||
|
||
Additional named arguments may optionally be included: | ||
|
||
- If C<$inlined> is set to C<1>, the attribute created will behave as if | ||
it were declared with | ||
L<HAS|/language/nativecall#Embedding_CStructs_and_CUnions> as its scope. | ||
- If C<$has_accessor> is set to C<1>, then an accessor method for the | ||
attribute will be generated for the attribute's package upon | ||
composition. | ||
- If C<$is_built> is set to C<1>, then this attribute will behave as if | ||
it had the L<C<is built>|#trait_is_built> trait applied to it. | ||
- If C<$is_bound> is set to C<1>, then this attribute will behave as if | ||
it had the L<C<is built>|#trait_is_built> trait applied to it with | ||
C<:bind> as its argument. | ||
|
||
The remaining named parameters are heavily dependent on Rakudo's | ||
internals, and are not something that should ordinarily be relied upon. | ||
|
||
=for comment | ||
That last sentence is a bit of a lie since there are a couple other | ||
named parameters that may be useful in some niche cases, but container | ||
descriptors and how autovivification works internally are undocumented | ||
as of writing. | ||
|
||
=head2 method name | ||
|
||
Defined as: | ||
|
||
method name(Attribute:D: --> Str:D) | ||
|
||
Returns the name of the attribute. Note that this is always the private name, | ||
|
@@ -176,11 +233,26 @@ so if an attribute is declared as C<has $.a>, the name returned is C<$!a>. | |
my $a = Foo.^attributes(:local)[0]; | ||
say $a.name; # OUTPUT: «@!bar» | ||
|
||
=head2 method package | ||
=head2 method type | ||
|
||
Defined as: | ||
method type(Attribute:D: --> Mu) | ||
|
||
method package() | ||
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)» | ||
|
||
=head2 method package | ||
|
||
method package(Attribute:D:) | ||
|
||
Returns the package (class/grammar/role) to which this attribute belongs. | ||
|
||
|
@@ -192,8 +264,6 @@ Returns the package (class/grammar/role) to which this attribute belongs. | |
|
||
=head2 method has_accessor | ||
|
||
Defined as: | ||
|
||
method has_accessor(Attribute:D: --> Bool:D) | ||
coke marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
||
Returns C<True> if the attribute has a public accessor method. | ||
|
@@ -209,8 +279,6 @@ Returns C<True> if the attribute has a public accessor method. | |
|
||
=head2 method rw | ||
|
||
Defined as: | ||
|
||
method rw(Attribute:D: --> Bool:D) | ||
|
||
Returns C<True> for attributes that have the "is rw" trait applied to them. | ||
|
@@ -226,8 +294,6 @@ Returns C<True> for attributes that have the "is rw" trait applied to them. | |
|
||
=head2 method readonly | ||
|
||
Defined as: | ||
|
||
method readonly(Attribute:D: --> Bool:D) | ||
|
||
Returns C<True> for readonly attributes, which is the default, or C<False> for | ||
|
@@ -244,8 +310,6 @@ attributes marked as C<is rw>. | |
|
||
=head2 method required | ||
|
||
Defined as: | ||
|
||
method required(Attribute:D: --> Any:D) | ||
|
||
Returns C<1> for attributes that have the "is required" trait applied, or C<Mu> | ||
|
@@ -261,28 +325,22 @@ is applied with a string, then that string will be returned instead of C<1>. | |
say $addr.required; # OUTPUT: «1» | ||
say $new-books.readonly; # OUTPUT: «"we always need more books"» | ||
|
||
=head2 method type | ||
=head2 method is_built | ||
|
||
Defined as: | ||
method is_built() | ||
|
||
method type(Attribute:D: --> Mu) | ||
Returns C<True> if the attribute had the L<C<is built>|#trait_is_built> | ||
trait applied to it, otherwise returns C<False>. | ||
|
||
Returns the type constraint of the attribute. | ||
=head2 method is_bound | ||
|
||
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 is_bound() | ||
|
||
=head2 method get_value | ||
Returns C<True> if the attribute had the L<C<is built>|#trait_is_built> | ||
trait applied to it with C<:bind> as an argument, otherwise returns | ||
C<False>. | ||
|
||
Defined as: | ||
=head2 method get_value | ||
|
||
method get_value(Mu $obj) | ||
|
||
|
@@ -299,8 +357,6 @@ used with care. Here be dragons. | |
|
||
=head2 method set_value | ||
|
||
Defined as: | ||
|
||
method set_value(Mu $obj, Mu \new_val) | ||
|
||
Binds the value C<new_val> to this attribute of object C<$obj>. | ||
|
@@ -320,8 +376,6 @@ used with care. Here be dragons. | |
|
||
=head2 method gist | ||
|
||
Defined as | ||
|
||
multi method gist(Attribute:D:) | ||
|
||
Returns the name of the type followed by the name of the attribute. | ||
|
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.