On Sun, Aug 27, 2000 at 10:31:05AM -0700, Nathan Wiger wrote:
> > The defined permissions are:
> > 
> >     '!', which forces the method call to fail, without further ado L<[5]>, and
> Isn't '!' the same as not specifying ':accessible', since the autoaccessor
> method therefore won't exist and either the defined class one or AUTOLOAD
> will still be called?
No.  Using !x explicitly disallows the method call in context x, even if
there is class one, or an AUTOLOAD, or a superclass one.  The idea is that
you can specify !r, and avoid the expensive fallbacks.


> >     '+', which makes the autoaccessor handle the call
> And isn't '+' the same as specifying ':accessible'?
Well, it's the same thing as specifing the raw letter.


> >     '~', which makes the autoaccessor fail, but allow traditional ways
> >          of handling the method call..
>  And how could you ever use '~'? 
> > A context with a '~' permission is the same as not specifying the
> > context letter at all L<[7]>, and is included only for completeness.

"~x" is the same as not specifing the letter at all (except for r!), and is
included only for parellelisim, along with "+x".  That is to say, its there
so you can write lists of '\Wr\Ww\Wm' for all possible sets of autoaccessor
types.

The only importnat one is "!", which lets you bypass the normal search for a
method, making it fail immediatly.  This should increase speed, or let you
simply disinherit a method call from a parent.


>    # ...
>       $self->{name} : access = "Nate"; 
>    # ...
>  
>    sub name {
>        # ...
>    }

> Then just specifying ':access' should cause it to override name(), which
> is in Perl already ("subroutine name() redefined..."). 
The autoaccessor isn't a sub, it just behaves as if it were.  This is the
central point of autoaccessors.  The idea is that they should be faster then
a method call, because you never change scope.  This won't give an error;
its a quite normal use.  The sub name will only get called in lvalue or
mutator context, because the rvalue contexts will see the autoaccessor first.

> If I then drop
> the ':access', name() will be called. And if name() didn't exist, then
> AUTOLOAD would be called. The !,+,~ permissions uselessly duplicate
> this, as far as I can tell.
With the exception of !, you're right

> > The context can be:
> > 
> >     'r' for rvalue (or 'r' for read)
> >     'l' for lvalue (or 'w' for write)
> >     'm' for mutator (which has no synonym) L<[6]>
> 
> I don't see why you'd want to restrict l/r sides if they're hash keys.
> This is implicit in making them readonly. 
Making them readonly makes all hash writes fail on them.  This is only for
the autoaccessor.  And remember, ~w just makes the autoaccessor not exist
for lvalue contexts of the autoaccessor.  It doesn't impede a normal sub,
nor _explicit hash access_.

If you had an :accessable('rw') attribute on a readonly key, the write half
would always fail, yes.  But writes using hash synthax ($obj->{foo}) would
also die, which they wouldn't with :accessable('r') (which is the default).

> If the user tries to use a
> readonly variable in an lvalue assignment, then it's an error. And
> telling them they can't use a writeable value on the l side makes that
> readonly implicitly. 
It makes the lvalue sub not exist.  That has many of the same effects, but:
1) Doesn't make hash access (especially from within your class!) fail.
2) If the 'w' is a '~w' (or unspecified), it allows a normal method to take
   over.

> So I would drop this, it's unnecessary and complex. All of it is taken
> care of by a :constant keyword. Just include a :constant attribute for
> those things you want readonly:
> 
>      $self->{DEFAULT_DIR} : access, constant = '/usr/bin';
>      $self->{name} : access = "Nate";
>      $self->{peers} : access = undef;

For your DEFAULT_DIR attribute, this makes C<$self->{DEFULAT_DIR}
='/usr/local/bin';> fail from within your class, which probably isn't what
you wanted.  If you had just specified :access, that wouldn't be the case.

Also, this wouldn't let you write code like:
sub DEFAULT_DIR :lvalue {
 $self = shift;
 $val = shift;
 
 if ((substr $val, -1) = '/') {
  $val = substr $val, 0, length($val-1);
 }
 
 $self->{DEFAULT_DIR} = $val;
}

Note that this code doesn't bother dealing with rvalue cases, since they've
been taken care of (with minimal possible overhead) by the autoaccessor.
(Note that this assumes some lvalue subs stuff that isn't fully hashed out
yet.)

I think in quite a number of attributes need processing to be set, but are
just fine being fetched.

> That is a lot simpler and seems to feel a lot better. 
I quite agree, and I'd rather have some cleaner way of specifing stuff like
this, but I think it needs to be at the level of the :autoaccessable
attribute.  The accessor is a way of getting at the key's value, but not the
only way.

> Finally, one thing that you should address is how to handle multi-level
> hashes:
> 
>      $self->{CONFIG}->{DEFAULT_DIR} : access, constant = '/usr/bin';
>      $self->{STATE}->{name} : access = "Nate";
>      $self->{STATE}->{peers} : access = undef;
> 
> Which is how I store data internally in my modules. Seems to me that you
> could make Perl Do The Right Thing by implicitly remembering the proper
> hash level:
> 
>      $self->DEFAULT_DIR   # $self->{CONFIG}->{DEFAULT_DIR}
>      $self->peers         # $self->{STATE}->{peers}
>      $self->name          # $self->{STATE}->{name}
> 
> Then, if someone defined the same end node in multiple levels and tried
> to use ':access' on both of them, simply issue a "subroutine
> DEFAULT_DIR() redefined at line..." warning.
> 
>      $self->{CONFIG}->{DEFAULT_DIR} : access, constant = '/usr/bin';
>      $self->{STATE}->{DEFAULT_DIR} : access;  # "sub redefined" warning

I've got only one idea of how to do this well, and you aren't going to like
it...  A deref attribute, which always dereferences the key's value.
That way, you'd make 
$self->{name} :accessable(':deref') = \$self->{STATE}->{name};

Doing it your way seems a little too DWIDM (Do What I Didn't Mean).  For
example, this could easily make things that you considered implementation
details into methods (if, say, CONFIG was an object that used autoaccessors
for _your_ convience, and not that of your user.)

Also, I'm firmly of the opinion that a scalar shouldn't know what contains
it, which your suggestion would break.

        -=- James Mastros


-- 
-----BEGIN GEEK CODE BLOCK-----
Version: 3.1
GU>CS d->-- s-:- a20 C++ UL+++@ P+++>+++++ L++@ E-() N o? K? w@ M-- !V
PS++ PE Y+ PGP(-) t++@ 5+ X+++ R+ tv+ b+++ DI+ D+ G e>++ h! r- y?
------END GEEK CODE BLOCK------

Reply via email to