John Williams writes:
> I want to get from here
>
> method bar_attr(?$val) is accessor {
> $.bar_attr = $val if exists $val;
> return $.bar_attr;
> }
>
> to here
>
> method bar_attr() is rw {
> return my $x is Proxy (
> for => $.bar_attr,
> FETCH => { $.bar_attr },
> STORE => { $.bar_attr = $_ },
> );
> }
>
> using a break-the-rules trait called accessor.
I think this is a good idea. Proxies are a little advanced for someone
who, say, comes from C# and doesn't understand tying yet. I think
you're going about it wrong, though. Here's how I imagine this working:
method bar_attr() will access -> $self: ?$val {
$.bar_attr = $val if exists $val;
return $.bar_attr;
}
Or, alternatively:
method bar_attr() will get { $.bar_attr }
will set { $.bar_attr = $_ }
And the traits C<access>, C<get>, and C<set> define C<do> to do the
right thing. The only trickyness that I see is getting C<get> and
C<set> to work together, since they each need to define part of the same
proxy class.
> I'm not sure what method gets called when a trait is applied to something,
> so I will assume that APPLY is called with the something it is applied to
> as the invocant.
>
> trait accessor {
> my $proxy is Proxy;
>
> method APPLY( Code $acc : ) {
I don't think that's right. That means, to apply the trait, you call
this way:
&bar_attr.accessor::APPLY;
Where I would think it would be something more like:
accessor.APPLY(&bar_attr);
Implying a signature like:
method APPLY(Code $acc is rw) {...}
> # "Proxy" is a trait/role with FETCH and STORE attributes (?)
> $proxy.FETCH = { $acc() };
> $proxy.STORE = { $acc($^a) };
> # Proxy.for is not set, since I do not know what is being
> # proxied; I only know how to access it.
>
> # add the rw trait
> $acc but= rw;
C<rw> is a trait, not a role. So you can't C<but> it on. Probably.
> # wrap the applyee
> $acc.wrap( sub (?$val) {
> $proxy = $val if exists $val; # so $foo.bar(1) still works
> return $proxy;
> } );
> }
> }
That looks okay to me, little as I know about traits. I'm a little
uneasy about declaring the Proxy as a lexical in trait scope; I'd be
inclined to declare it as a lexical in the C<APPLY> routine, or even
in the anonymous sub that you're wrapping with.
Luke
> I *think* that accomplishes my goal of simple-to-write accessors (for
> scalars, at least). Now I only have to change the signature in Damian's
> example, and I think it will work for $foo.bar_attr -= 9999999;
>
> method bar_attr(?$rvalue) is accessor {
> if exists $rvalue {
> croak "Negative value" if $rvalue < 0;
> $.bar_attr = $rvalue;
> }
> return $.bar_attr;
> }
>
> Or maybe I'm missing the point completely.... comments? rebuttals?
>
> ~ John Williams
>
>