I was going to go on about a few ways to do this, but after I did I realized that only one option is viable. So, let's try this on for size:
Vtables are chained. That means each vtable has a link to the next in the chain. It *also* means that each call into a vtable function has to pass in a pointer to the vtable the call came from so calls can be delegated properly. If we don't want this to suck down huge amounts of memory it also means that the vtable needs to be split into a vtable header and vtable function table body.
Downside there is that we have an extra parameter (somewhat pricey) to all the vtable functions.
This is sort of icky. What about dynamically constructing vtables and caching
them? We'd probably need some sort of mangling scheme, but it wouldn't be too
hard; maybe just the ordered list of packages separated by NULs or something.
Then again, though, any sort of stacking runs into data collisions in the PMC.
So maybe we just need lots of vtable types. Ties should probably be their own vtable (or one each for tied scalars, hashes, and arrays); read-only-ification should maybe be a special case that actually does dynamically create (and
cache, if need be) vtables, replacing ->set_* and ->morph with functions
that throw an exception. For thread-sharing: proxies seem to be standard? What other attributes or traits or whatever actually expect to still be able to directly access the underlying variable? (Ties and overloads, for instance, _don't_ - they have to provide their own backing storage.)
I suppose what I'm getting down to is that the intelligence should just be
in the compile-time PMC class generator, not dynamic in the runtime. Except maybe for read-only-ification.
-- BKS