Audrey Tang audreyt-at-audreyt.org |Perl 6| wrote:
John M. Dlugosz wrote:
A method can refer to private attributes etc. in other objects than
self. This is unlike Smalltalk and like C++. Which objects? Obviously,
those that _have_ them in the first place.
Correct, though those classes also has to trust the calling class:
class MyClass { has $!attr; trusts YourClass }
class YourClass {
method foo (MyClass $obj) {
$obj!MyClass::attr; # Access to $obj's private attr
}
}
So, do classes trust their derived classes by default? Is trust itself
inherited?
In this example, as in S12, why do you have to specify the MyClass::
prefix? I thought you would only need this to refer to a specific class
in the ISA list and not necessarily the one defined in or visible in the
declared class.
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.
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.
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?
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?
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.
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.
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.
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