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