On Tue, 20 Apr 2004, Luke Palmer wrote:

> John Williams writes:
> > On Tue, 20 Apr 2004, Luke Palmer wrote:
> > > There.  Now here's the important part: in order to *use* all this, you
> > > import whatever module defines it, and then say:
> > >
> > >     class Dog {
> > >         method foo (?$arg) is accessor {
> > >             # accessor code here
> > >         }
> > >     }
> > >
> > > If that's not easy enough for you, well, you're probably out of luck.
> >
> > It would be even easier if we could put the read-accessor-code and
> > write-accessor-code in different methods.
> >
> >     class Dog {
> >         multi method foo { ... }
> >         multi method foo ($arg) is accessor { ... }
> >     }
>
> Ugh!  That's what I originally suggested, and it was shot down it was.
>
> My first solution to your problem introduced the traits C<get> and
> C<set>, allowing you to write it like this:
>
>     class Dog {
>         method foo ()
>             will get { ... }
>             will set { ... }
>         { }  # usually empty
>     }
>
> I guess I bogged down that message with the implementation, so the
> result may have been easy to miss.

Well, I think we've come full circle.  The get/set is the same as the
presumed current implementation, just with different keywords:

    class Dog {
        has $.foo
            will FETCH { ... }
            will STORE { ... }
        ;
    }

I'm not saying there is anything wrong with that, but John Siracusa is
asking for something different, I think.  A simple accessor which looks
like a method without having to play with Proxy, FETCH, STORE, etc.
If it still looks like $obj.foo = 1 outside the class, that's good too.
(Delphi and C# can do it; why can't we?)

Getting the multi-methods foo()/foo($) to automagically act as the
reader/writer for a virtual foo attibute seems like it would fulfill
his requirements.  foo() already works for the reader, but foo($) needs
some help to make $obj.foo = 1 call $obj.foo(1).

Here's a feeble attempt to do what I suggested:

   role accessor {
        has $.accessor = 1;
        multi sub trait_auxiliary:is( accessor $trait, &meth(Any) ) {
            my $class = &meth.meta.class;
            class $class is extended {
                # class methods take precedence, so install a method
                # in the class "is default" so it gets called first
                multi method $meth.meta.name () is default {
                    return my $proxy is Proxy (
                        STORE => { &meth($^val) },
                        FETCH => {
                            my ($reader) =
                                grep !$_.meta.default ,
                                $class.meta.getmethods;
                            &$reader;
                        },
                    );
                }
            }
            $meth does accessor;
        }
    }

    class Dog {
        multi method foo { ... }
        multi method foo ($arg) is accessor { ... }
    }

    my Dog $spot;
    $spot.foo++;

~ John Williams






Reply via email to