Interesting!
I'm trying to avoid to overbake :) the Proxy, by assigning it to a 'state'
variable or creating a method on-the-fly, in the hope it's treated as a
closure, but no luck so far:
class A {
has $.a;
submethod BUILD {
A.^add_method('proxy', my method proxy(A:) {
say 'Creating a proxy method...';
Proxy.new(
FETCH => { $!a },
STORE => -> $, $value { $!a = $value * 2 }
)
});
}
method a()
{
self.proxy;
}
}
my A $a .= new;
$a.a = 21;
say $a.a;
Output:
Creating a proxy method...
Creating a proxy method...
42
On Tue, Nov 14, 2017 at 7:38 PM, yary <[email protected]> wrote:
> 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
>>
>
>
--
Fernando Santagata