On Fri, Apr 04, 2008 at 07:01:32PM -0500, John M. Dlugosz wrote:
> That is, a derived class, assuming it was trusted, could use 
> $self!BaseName::attr to prevent confusion with something named self!attr 
> that ordinarily hides it.

Which is never a problem anyway, since private attributes are never,
ever inherited, and are even off in their own namespace so they're
completely invisible to a derived class.  Suppose you derive:

    A -> B -> C

Suppose B defines $!foo as a private attribute.  This is invisible to
C, to the extent that if A defines a public $.foo, it is visible in C.
Private names are never allowed to clobber public names.

> And a syntax question for you:  Above, I just assumed $self is the 
> explicitly-named invocant.  How do you access the attribute if using the 
> self keyword, which does not have a sigil?  If it has $!attr and has 
> @!attr, that is important.  I realize this is not an issue when using 
> method calls (including accessor functions) on self.

self!BaseName::attr should work, assuming BaseName trusts us.

>>> Does the variable used as the invocant, or return value if it is an 
>>> expression,
>> > have to be statically typed as being of the identical class?
>>
>> The $obj above must be evaluated to an object of class MyClass.
>>
>> AFAICS, the spec doesn't really say if a derived class needs to explicitly 
>> trust YourClass for it to be used this way:
>>
>> class MyDerivedClass is MyClass {};
>> YourClass.foo(MyDerivedClass.new(attr => 1)); # Not sure if this works.
> "the spec doesn't say"  hence my confusion.  So will Larry rule on that, or 
> should we discuss it in detail, or should I just make up something in my 
> proposed doc edit?

As pointed out elsewhere, the spec does say, if you shake it hard
enough. :)

> If your example does work, it means that in general the BUILD can comb 
> arguments out for each class in the hierarchy, rather than only being 
> allowed to specify arguments to defined constructors for the base classes, 
> as in C++.  Is that good or bad?  Just how would you say the latter, 
> anyway?

See S12:680 and following for how to pass protoobjects representing
partial construction without having to actually create intermediate
objects.

>>> If class C { has $.a; ... }, then I understand that members may refer to
>>> $.a directly but outside of the scope of members defined in the class
>>> they can only be reached by accessors, a() as a method call.
>>
>> Well, $.a is exactly the same as $(self.a) -- see S12/"are just shorthands 
>> of C<self.foo>" for the definition.
>>
>> Methods in class C may call $!a, which is the private accessor method.
>> Outside the scope, private methods of class C are invisible.
>>
> OK, I think I'm beginning to see. $.x is not "variable-like", but a 
> shortcut for $(self.x()), and always is.  You don't name an object with 
> this form, ever, as it only works on self. 
> That is why the ! forms don't have a "unary form".  It could certainly be 
> explained better in the document.  Your retelling is already helpful.

Well, the main reason there is no unary ! form is actually that
prefix:<!> already means something else in C-derived languages.  :)

>>> But, it is also stated that in derived and trusted classes, and even in
>>> the class itself, $.a is an accessor call?
>>
>> Well, $.a is merely shorthand for $(self.a) so derived classes can call it 
>> just fine.  However in trusted classes, $.a wouldn't make much sense,
>> as you need to use either $obj.a or $obj!YourClass::a there.
>>
>>> Is this accessor different from the
>>> function form used outside the class? Why keep the variable syntax?
>>
>> Because it's jolly convenient, especially in interpolated strings, I 
>> suppose:
>>
>> say "My position is $.x - $.y - $.z";
>>
>>> I'm getting a picture of 3 forms of access: Really direct, direct but
>>> asking the class to access it rather than knowing how storage works, and
>>> indirect that may involve your own code to do other things besides just
>>> get/set the attribute. But I think the middle one can be handled
>>> invisibly by the compiler -- it's no different from a tied hash.
>>
>> The middle one is not that different from the first one, because from an 
>> implementation viewpoint, once YourClass trusts MyClass, then code in 
>> MyClass might as well have knowledge about how the storage works.
> But it looks like there is no middle one.

Yes, there is no middle, by design.  It's either concrete storage,
hence non-virtual, or it's abstract and hence virtual.  And even the
class itself is encouraged to distinguish those usages, so it should
use $!foo when it means the storage, and it should use $.foo when it
means the concept, so that a derived class can override it.

> Besides "how the storage works", I'm thinking of the multiple-base 
> composition issues.  The attribute may be stored in different places 
> depending on the concrete type, and the method is called on a type derived 
> from the one it is written in.

Every class maintains its own concrete, which is of no business to
anyone else, including derived classes.  There is nothing like
protected in Perl 6.  The closest you can get to it is "trusts",
and that's independent of class hierarchy.

>>> How private is private? I wonder if what you've called private things
>>> are really more like "protected" in C++ (accessible by the derived
>>> class) and that 'my' attributes are really private, as are submethods.
>>> It's all confused. Who is allowed to access what?
>>
>> No, private methods are not accessible from derived classes, unless the 
>> base class explicitly trusts them -- See L12/"the exclamation form may be 
>> used only in the actual class, not in derived classes".
>>
>> Cheers,
>> Audrey

It is my understanding that even Bjarne thinks "protected" is a bad idea
these days...

Larry

Reply via email to