On Fri, 27 Feb 2004, Luke Palmer wrote: > John Williams writes: > > I want to get from here > > > > method bar_attr(?$val) is accessor { > > $.bar_attr = $val if exists $val; > > return $.bar_attr; > > } > > > 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; > }
Well, I like being able to just say "is accessor" better... > Or, alternatively: > > method bar_attr() will get { $.bar_attr } > will set { $.bar_attr = $_ } ... but this is good. I'd forgotten about C<do>. > 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. It's just setting the FETCH and STORE attributes on a shared Proxy class, if I understood that right. Maybe the traits put a Proxy property on the method they are applied to, and all modify that same Proxy property. Then, if the get and set traits are just mixed-in with the Method class, $self for the trait would refer to the Method itself, so they can just define C<do> to return the Method's Proxy property. # create the Proxy property $self but= Proxy.new(); # add the parts defined by traits $self.Proxy.STORE = $self.set if exists $self.set; $self.Proxy.FETCH = $self.get if exists $self.get; # C<do> is always the same $self.do = { $self.Proxy }; Even simpler than wrapping! Or maybe C<get> and C<set> are parts of the Accessor trait, so you need to apply it to use them. method bar_attr() is accessor will get { $.bar_attr } will set { $.bar_attr = $_ }; method bar_attr(?$val) is accessor { $.bar_attr = $val if exists $val; return $.bar_attr; } And we can have it both ways: trait accessor { [hand-waving declaration for the trait APPLY method] { $self but= Proxy.new(); if (exists $self.do) { $self.Proxy.STORE = { $self.do($^a) }; $self.Proxy.FETCH = { $self.do() }; } else { $self.Proxy.STORE = $self.set // { die "read-only!" }; $self.Proxy.FETCH = $self.get // { die "write-only!" }; } $self.do = { $self.Proxy }; } } Am I off the deep end yet? > > trait accessor { > > my $proxy is Proxy; > > > > method APPLY( Code $acc : ) { > > I don't think that's right. I'm certain it's wrong. But I had to put something there. It could also be that the trait is constructed at the same time as the object it applies to, and its CREATE method gets called with the same arguments. Waiting for A12... > > # "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. I had it in the wrapper sub in the first version, but I didn't like that it was recreating the Proxy object every time someone accessed the accessor. So I moved it to where I only needed to create it once. ~ John Williams