On Tue, 20 Apr 2004, Brent 'Dax' Royal-Gordon wrote:
> John Williams wrote:
> > 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?)
>
> C# does it as
>  ...

Interesting.  Here's the Delphi version, for comparison.

    // the trivial attibute
    SomeNumber : Integer;

    // the virtual property
    // read/write can refer to either a variable or a func/proc
    property VirtWrite : Integer read SomeNumber write SetSomeNumber;

    procedure SetSomeNumber( in : Integer );
    function GetSomeNumber : Integer;

The big win being that one can replace the trivial attribute with a
property, and the interface stays the same.

The perl6 version of that would of course be

    class Dog {
        method getfoo returns Int {...};
        method setfoo(Int $v) {...};

        has Int $.foo will FETCH \&getfoo
                      will STORE \&setfoo;
    }

I'm not saying there is anything wrong with that.  I completely agree with
Larry that the correct interface for accessors is $x = $obj.foo = $y;

I'm mainly curious if there is an even simpler way to define the
implementation of the accessor than the above.

The simplest possible rw accessor is

    method foo is rw { $.foo };

which basically just makes $.foo available to the outside.  When you get
more complex and need to intercept the reading and writing, it's clear
that returning a Proxy object is the best way (so far proposed) to do the
right thing for ($x = $obj.foo = $y) and ($obj.foo++).  For convenience
and to avoid being uncool-retro, one also wants to separate the accessor
into read and write multi methods.

    multi method foo() returns Int {...};
    multi method foo(Int $v) {...};

    has Int $.foo will FETCH { .foo } # ignore the name conflict for now
                  will STORE { .foo($^value) };

The declaration of the "has" variable to delegate to the above methods now
becomes repetitive boilerplate code, which could be eliminated by a clever
trait.  It also interferes with the obvious name for a multi method
reader.

foo() obviously works fine (by itself) as a reader, but foo($)  needs some
help.  Somehow foo() has to return a Proxy which delegates STOREs to
foo($), and FETCHes to itself.  Since foo() works fine as a read-only
accessor by itself, a minimalist approach shouldn't require foo() to add a
trait.  foo($) needs the help so it should get the trait.

So I propose (in the request-for-comments sense, not the "this should
go into perl6 core" sense) that given a trivial accessor:

    has $.foo is rw;

the minimal replacement with full read/write control would be this:

    multi method foo() {...};
    multi method foo($v) is accessor {...};

(And the accessor trait somehow does the magic to define a new foo() which
returns a Proxy which delegates to the declared foo() or foo($).)

~ John Williams


Reply via email to