Account Options

  1. Sign in
The old Google Groups will be going away soon, but your browser is incompatible with the new version.
Google Groups Home
« Groups Home
Message from discussion Thinking about Accessors
The group you are posting to is a Usenet group. Messages posted to this group will make your email address visible to anyone on the Internet.
Your reply message has not been sent.
Your post was successful
 
From:
To:
Cc:
Followup To:
Add Cc | Add Followup-to | Edit Subject
Subject:
Validation:
For verification purposes please type the characters you see in the picture below or the numbers you hear by clicking the accessibility icon. Listen and type the numbers you hear
 
John Williams  
View profile  
 More options Feb 27 2004, 9:48 pm
Newsgroups: perl.perl6.language
From: willi...@tni.com (John Williams)
Date: Fri, 27 Feb 2004 19:37:57 -0700 (MST)
Local: Fri, Feb 27 2004 9:37 pm
Subject: Thinking about Accessors
This may all be explained in the upcoming A12, but I'm trying to get
Accessors figured out in my head, and I had a few questions and comments.

===== paraphrased from Damian in http://www.nntp.perl.org/group/perl.perl6.language/9576)

it seems very likely that if you write:

        class Foo { # version 1
                has $.bar_attr is public;
        }

then you'll get an automagically created lvalue accessor method that will
allow you to write:

        my $foo = Foo.new();
        $foo.bar_attr = 1;

and then later define a real C<Foo::bar_attr> method to encapsulate it:

        class Foo {     # version 2
                has $.bar_attr is public;
                method bar_attr is rw($rvalue) () {
                        if exists $rvalue {
                                croak "Negative value" if $rvalue < 0;
                                $.bar_attr = $rvalue;
                        }
                        return $.bar_attr;
                }
        }

=====

From Damian's comments I conclude:

There will be one autogenerated accessor, with the same name as the
attribute (not get/set pairs).

It will work correctly in all these cases:

    $x = $foo.bar_attr;        # read
    $foo.bar_attr = $x;        # write
    $x = $foo.bar_attr = $y;   # write then read

My question is about these cases:

    $foo.bar_attr += $z        # read then write
    $foo.bar_attr++;

L<Apocalypse 6/Lvalue subroutines> would seem to apply here because of the
"is rw" trait.  It says I will need to return a proxy object in order for
these cases to work right, because I only get to return from the accessor
once, and subsequent writes are performed on the proxy object.

In fact, I think Damian's example above (written long before A6, so not
his fault) would fail to croak if I wrote:

    $foo.bar_attr = 12;
    $foo.bar_attr -= 100;

According to A6, it should probably be written like this:

    method bar_attr() is rw {
        return my $bar_proxy is Proxy(
            for => $.bar_attr,
            STORE => {
                croak "Negative value" if $_ < 0;
                $.bar_attr = $_;
            },
        );
    }

But if we *always* have to return a proxy object, in case someone uses +=
on our attribute, I can see users yearning for the simplicity of get/set,
even if it is not as syntactically sweet.

I really like the "is Proxy" for tie-ing things, but I keep thinking its a
bit of overkill for accessors.  From an easy-things-should-be-easy
perspective, I wouldn't mind at all if $object.attr += 3 magically
arranged to call an accessor twice: once to read, and once to write.

The accessor would have a simple signature:

    method bar(?$val) {...}

It is simple to know if the accessor is reading or writing:

    method bar(?$val) {
        print "Ima reader" if want;
        print "Ima writer" if exists $val;
    }

But I am asking for magic with that, because $foo.bar is no longer what it
looks like (a method with no arguments).  "$foo.bar += 3" is transformed
into "$for.bar($foo.bar() + 3)".  I may lose things like the ability to
bind, etc.

A proxy should be able to do anything, it just doesn't do it as simply as
I want.  So it occurs to me that it might be possible to implement the one
in terms of the other.  To do that I need to explore another area from the
upcoming apocalypse (traits), so forgive my deficient syntax.

I want to get from here

     method bar_attr(?$val) is accessor {
        $.bar_attr = $val if exists $val;
        return $.bar_attr;
     }

to here

     method bar_attr() is rw {
        return my $x is Proxy (
           for => $.bar_attr,
           FETCH => { $.bar_attr },
           STORE => { $.bar_attr = $_ },
        );
     }

using a break-the-rules trait called accessor.

I'm not sure what method gets called when a trait is applied to something,
so I will assume that APPLY is called with the something it is applied to
as the invocant.

    trait accessor {
        my $proxy is Proxy;

        method APPLY( Code $acc : ) {
            # "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;

            # wrap the applyee
            $acc.wrap( sub (?$val) {
                $proxy = $val if exists $val; # so $foo.bar(1) still works
                return $proxy;
            } );
        }
    }

I *think* that accomplishes my goal of simple-to-write accessors (for
scalars, at least).  Now I only have to change the signature in Damian's
example, and I think it will work for $foo.bar_attr -= 9999999;

        method bar_attr(?$rvalue) is accessor {
                if exists $rvalue {
                        croak "Negative value" if $rvalue < 0;
                        $.bar_attr = $rvalue;
                }
                return $.bar_attr;
        }

Or maybe I'm missing the point completely....  comments?  rebuttals?

~ John Williams


 
You must Sign in before you can post messages.
To post a message you must first join this group.
Please update your nickname on the subscription settings page before posting.
You do not have the permission required to post.