How should autovivification work?
This document still references YAP6 before the refactoring that caused the rename to SMOP. The logic is still valid, but the way the code works is considerably different.
here it would return a ProxyScalar that references %a and 'b'
__a_b = YAP6_HASH_LOOKP(%a, 'b'); // variable resolution not detailed here.
the same object with a coercion to hash, at this time,
_hash__a_b = YAP6_HASH(__a_b);
here it would return another ProxyScalar that references _hash__a_b and 'c'
__a_b_c = YAP6_HASH_LOOKP(_hash__a_b, 'c');
until now, nothing happened yet, just the proxy objects were created but no actual lookup was made yet. we have a lazy path to the container.
my $b := %a<b><c>;
The bind case, is at first, a capture creation, just like when using it into an argument list. So we have a two phase thing which is.
capture = YAP6_CAPTURE(/*invocant*/ NULL, /*positional*/ YAP6_LIST_CREATE(__a_b_c), /*named*/ NULL);
YAP6_BIND(/* this should be a signature, not detailed here*/ $b, capture);
After TimToady's clarification (and actual spec change), we now know that the capture never autovivifies, but only the binding does it. And only if the bound container is a rw container, so.
my $a is readonly := %a<b><c>; # doesn't autovivify
So, the capture is really just a way to defer the contextualization of the object and does nothing else.
The binding code is responsible for, when doing the actual bind, checking if the container itself is defined. If not and in the presence of a WHENCE closure, the object should be autovivified. But this requires the bootstrap...
for now, check SMOP OO Bootstrap