John Siracusa writes: > On 4/19/04 3:58 PM, Austin Hastings wrote: > >> I initially decide to accept the default accessors. > >> > >> $dog.name = 'Ralph'; > >> print $dog.age; > >> > >> This works well for a while, but then I decide to update Dog so that setting > >> the name also sets the gender. > >> > >> $dog.name = 'Susie'; # also sets $dog.gender to 'female' > >> > >> How do I write such a name() method? > > > > has $.name is rw > > will STORE { .set_name($^name); }; > > The "will STORE" stuff covers the easy cases, but can I extend it all the > way up to a name() that's a multimethod with a ton of optional args? I > supposed you can (technically) do all of that with "will STORE", but it > seems an odd place for what would more naturally be code in the name() > method itself.
I think a role on the attribute is not the right place to put it. What you're doing is returning a proxy object that knows how to set both the name and the gender. Here are a couple of implementations: class Dog { has $.name; has $.gender; method name() { return my $dummy is Proxy( for => $.name, STORE => sub ($in) { $.gender = /<Names::Female>/ ?? 'male' :: 'female'; $.name = $in; }, ); } } Yuck. Much nicer: class Dog { has $.name; has $.gender; method name() will get { $.name } will set -> $in { $.gender = /<Names::Female>/ ?? 'make' :: 'female'; $.name = $in; } { } } This is nothing new. So, for fun, here's the implementation of C<get> and C<set>: role get { multi sub trait_auxiliary:is(get $trait, &code: ?$arg) { wrap &code: { my $result := call; return my $dummy is Proxy( for => $result, FETCH => $arg, ); }; } } role set { multi sub trait_auxiliary:is(set $trair, &code: ?$arg) { wrap &code: { my $result := call; return my $dummy is Proxy( for => $result, STORE => $arg, ); }; } } Luke