Today Leo sent me a set of design notes, including his recent thinking about how Parrot's PMC layout and interfaces may be improved, allegedly inspired by pugs/docs/quickref/data. Coincidentally, I was feeling unhappy about the steadily-growing vtable of PILN's NativeObj structure, so I implemented Leo's design, and it worked beautifully.
The basic idea is that instead of having a large fixed set of things that all objects may do, we split them out into interfaces, which are simple mappings from method names to native code. At class composition time, the class selects a representation for its object by mixing in one or more interfaces.
The chosen interfaces determines which primitive operations the object can perform, which stays immutable during the entire runtime (just like the old vtables did), and as such may still be checked statically.
Under this scheme, we don't need to allocate stub throw-an-execption for value classes's set method, and the distinction of Containers is clear: unlike ordinary Objects, they do not use the p6opaque representation (set_attr, get_attr...). I have just coded in p6array and p6hash representations, with primitive operations such as fetch_elem and store_elem.
This also addressed the problem of how attributes are handled when we extend builtin classes with Perl 6 code. Because "has $!x = 3" ultimately desugars into set_attr operations, which does not exist in a boxed p6integer, code like "class ::Int is extended { has $!foo }" can be rejected at compile time, which is probably a good thing.
Tomorrow I'll move to ::Args and ::Sigs, and ::Code after them if all works out. Then we'll add some sugar to it and serve the dish by compiling PIL2 to it. It's already smelling good...
Comments