Neat! Just read the Proxy class doc at https://docs.perl6.org/type/Proxy
Instead of hooking into any accessor magic, this solution creates a Proxy
object that lives inside the "a" method. Every time you use the "a" method,
it generates a new Proxy object, which will either set or retrieve the $!a
attribute from the A object.
Two minor quibbles, and since I'm not the author or user, take them with a
grain of salt:
" $.a if you want to be able to assign with .new " - in that case, $!a
won't go through the modifications.
class A {
has $.a;
method a() {
Proxy.new(
FETCH => { $!a },
STORE => -> $, $value { $!a = $value * 2 }
)
}
}
my $a = A.new(a => 23);
dd $a.a; # 23
$a.a = 34;
dd $a.a; # 68
A way to fix that, is to have the STORE function be a named routine that
both the proxy object & a TWEAK submethod can use, as each sets $!a.
The other quibble, is that it creates and discards the proxy object with
each call. (Not at all a problem functionally and likely not anything that
would affect performance either.) Here's a demo
class A {
has $!a;
method a() {
say "baking a new Proxy object for class A";
Proxy.new(
FETCH => { $!a },
STORE => -> $, $value { $!a = $value * 2 }
)
}
}
my $a = A.new(); # no output
$a.a = 34; # "baking..."
dd $a.a; # "baking...", "68"
-y
On Tue, Nov 14, 2017 at 7:09 PM, Elizabeth Mattijsen <[email protected]> wrote:
> This might it then:
>
> class A {
> has $!a; # $.a if you want to be able to assign with .new
> method a() {
> Proxy.new(
> FETCH => { $!a },
> STORE => -> $, $value { $!a = $value * 2 }
> )
> }
> }
> my $a = A.new;
> $a.a = 77;
> dd $a.a; # 154
>
> > On 14 Nov 2017, at 18:51, Fernando Santagata <[email protected]>
> wrote:
> >
> > Hi Liz,
> >
> > What I need is to preprocess the value before assigning it to an
> attribute.
> >
> > I would do that in Perl5/Moose, using "around", like this:
> >
> > package A;
> > use Moose;
> >
> > has 'attribute' => (is => 'rw', isa => 'Str');
> >
> > around [qw(attribute)] => sub {
> > my ($next, $self, $val) = @_;
> > return $self->$next unless $val;
> > return $self->$next(preprocess $val); # Preprocess the value before
> the assignment
> > }
> >
> > In this way I don't have to make an explicit call to the preprocessor
> any time I assign a value to that attribute, effectively removing that from
> the main program.
> >
> > I'm looking for a way to do that in Perl6.
> >
> > On Tue, Nov 14, 2017 at 6:11 PM, Elizabeth Mattijsen <[email protected]>
> wrote:
> > > On 14 Nov 2017, at 18:06, Fernando Santagata <
> [email protected]> wrote:
> > > I'm converting a program from Perl5/Moose.
> > > I have several classes, each has some attributes that need to be
> processed in the same way before being passed to other objects.
> > >
> > > When I was using Moose, I had some "around" methods that would
> automatically modify the value before delivering it to those attributes, so
> delegating the object to do the needed adjustments.
> > >
> > > Stripped to the bare bones, the thing that in Perl6 looks like this:
> > >
> > > class A {
> > > has $!a;
> > >
> > > method a($val?)
> > > {
> > > if $val.defined {
> > > # Modify $val in some way
> > > $!a = $val;
> > > } else {
> > > $!a;
> > > }
> > > }
> > > }
> > >
> > > my A $a .= new;
> > > # $a.a = 42; # This outputs an error
> > > $a.a(42);
> > > say $a.a;
> > >
> > > Any hint how to make it work as an assignment, instead of a method
> call?
> > > Better yet, is there a way to abstract that behavior in a role?
> >
> > I think you want “is rw” on a public attribute?
> >
> > class A {
> > has $.a is rw;
> > }
> > my $obj = A.new;
> > $obj.a = 42;
> > dd $obj;
> > ===========
> > A $obj = A.new(a => 42)
> >
> >
> >
> > Liz
> >
> >
> >
> > --
> > Fernando Santagata
>