I'm about to choose what language to use for a new project: Perl5 or Perl6. 6 wins so far except that it is missing Moo
's lazy attributes. The two implementations I found in modules are missing the key functionality. Hence, my attempt write my own implementation.
First problem I've got into is the content of attribute's .package
for one declared in a role. Consider the followin:
role HOW1 {
method compose ( Mu $class ) {
note "HOW1.compose";
nextsame;
}
}
role HOW2 {
method compose ( Mu $class ) {
note "HOW2.compose";
nextsame;
}
}
multi trait_mod:<is> (Attribute:D $attr, :$mooish!) {
note "Attribute's package.HOW: ", $attr.package.HOW;
note '$*PACKAGE.HOW: ', $*PACKAGE.HOW;
$attr.package.HOW does HOW1;
$*PACKAGE.HOW does HOW2;
}
class Foo {
has $.bar is mooish;
}
role FooRole {
has $.baz is mooish;
}
The output of the script follows:
Attribute's package.HOW: Perl6::Metamodel::ClassHOW.new
$*PACKAGE.HOW: Perl6::Metamodel::ClassHOW.new
HOW2.compose
HOW1.compose
Attribute's package.HOW: Perl6::Metamodel::GenericHOW.new
$*PACKAGE.HOW: Perl6::Metamodel::ParametricRoleHOW.new
HOW2.compose
As it is clearly seen from the output, applying a role to a metaclass always works for classes and only works for $*PACKAGE.HOW
with roles. Use of $*PACKAGE
instead of .package
could be considered a solution, but not the one I'd really like to use. (Though, if there is no better way...)
I would like to provide lazy functionality for private attributes too. Yes, this will be availabe with self!bar
syntax only, but this is a sacrifice I'm willing to make. 😉 The problem is that all the examples of custome-made accessor I found so far are using Attribute.set_value()
method which is way too low-level. I'd like to have something like this:
role MooishHOW {
method compose ( Mu $class ) {
my $accessor = $class.^add_private_method( 'bar1',
method () is rw {
note self.WHO, ".bar1";
Proxy.new(
FETCH => -> $o {
$!bar1;
},
STORE => method ( $val ) {
note "Storing";
$!bar1 = $val;
}
);
}
);
callsame;
}
}
multi trait_mod:<is> (Attribute:D $attr, :$mooish!) {
$attr.package.HOW does MooishHOW unless $attr.package.HOW ~~ MooishHOW;
}
class Foo {
has $.bar is mooish;
has $!bar1 is mooish;
method to-bar1 {
note "bar1 val:",self!bar1;
}
}
my $inst = Foo.new;
$inst.to-bar1;
But $!bar1
notation doesn't compile because of the scope (MooishRole
). Are there a trick I'm missing which would allow referencing a private attribute on self
?
Perhaps it is possible to make an attribute to be a Proxy
container? This would greatly simplify the overall logic of laziness implementation.
Attributes are always specified in the start tag (or opening tag) and usually consists of name/value pairs like name="value" . Attribute values should always be enclosed in quotation marks.
An attribute is defined as a quality or characteristic of a person, place, or thing. Real life individuals and fictional characters possess various attributes. For example, someone might be labeled beautiful, charming, funny, or intelligent.
Examples are height, skin color, hair color, and eye color of humans. The traits are determined not by a single gene but by multiple genes.
I have answered all my questions by finally achieving the target and released AttrX::Mooish module.
So far, the answer for the first question is: no. $*PACKAGE
is currently the only way.
Second question: have no answer, but the final code has to rely on set_value()
anyway.
The tricky one happened to be possible: set_value()
does binding of an attribue to a container making it possible to bind to a Proxy
object. No need to for sacrifices, private attributes can be accessed directly with lazyness working on them.
Thanks everybody, your answers let me work around some rough edges!
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With