Huh? $!salary is simply the name of the private storage area for the attribute. No calling involved, since the method already knows its own self, and whole point of $!salary is to tell the method it can access the storage directly rather than through a virtual method.
The extra information is only necessary when calling something private in another object.
I thought it's always a private accessor. The MOP knows how to really get at that slot, though this may be inlined and optimized down, it's logically an accessor submethod. $!salary will do something different in a P6opaque than in a P5hash or a dotNetImport etc.
So how does the compiler communicate with the meta-object protocol to ask "how do I generate code to access this slot?" if it's not a function provided by the MOP?
Given the normal public access semantics, "$.foo, @.foo, %.foo, &.foo are just shorthands of self.foo with different contexts" and "$.foo(1,2,3); # calls self.foo under $ context", the sigil of the attribute doesn't show up when accessing it, so you can't have attributes with the same base name but different sigils.
Is the same thing true with $!foo, @!foo, etc? After all,
"$!think($pinky) # short for $(self!think($pinky))"
and I can't imagine the grammar doing things differently depending on whether the token after it was declared as a method or an attribute. I don't see the ! becoming twigil-like for attribute names, right?
So, does $!foo appear to have a similar nature to $!bar (one of those is an attribute and the other is a submethod; which is which?) with respect to @!foo etc meaning the same slot in a different context? Or does it appear to be similar to a local variable, with the sigil and twigil being part of the name and @!foo being a different location?
We're kinda confusing levels here. There are really three viewpoints of an object:
I was speaking from the perspective of #2, not #3. From the #2 perspective, for any normal attribute without an explicit private accessor, $!foo and self!foo are largely interchangeable, give or take a sigil. The MOP may or may not make visible the call that implements $!foo, since $!foo is viewed under #2 as fundamentally a reference to the storage. The MOP is free to not implement method !foo at all if it can determine that it is unneeded,
either by analysis or just by being lazy about autoloading one. From the #2 viewpoint, $!foo is just a variable, and method !foo is a (possibly autogenerated) accessor to the variable.
- The external public view.
- The internal private view.
- The hidden MOP view
From the #3 perspective, sure, the fundamental accessor for the slot could be identical to method !foo, but then you're kinda hosed if the user wants to actually define the !foo method as a wrapper around $!foo, which would be an infinite regress if you confuse the user's slot accessor with the MOP's slot accessor. So unlike the situation with $.foo, the $!foo notation is not just syntactic sugar for a private accessor, and a private method must be called as self!foo.
So why would the user ever want to define their own private accessor? Primarily to mediate how much you want to dynamically "untrust" any other classes you've trusted by declaration.