Jon Lang had some good thoughts on this.
I want to clarify or expand on my proposal so it is more clearly understood.
1. First of all, and there may have been no confusion on this but I'll say it
When a class has multiple possreps, one main point here is that users could use
the class by way of the API implicitly defined by one possrep as if it were the
only one. Similarly, an ordinary class that doesn't explicitly use the possreps
feature is semantically the same as a class that does and declared exactly one.
Now, if it were the case that possreps did not have any attribute names in
common with other possreps, then users would never even need to mention a
possrep name when using it.
On the other hand, if (and there is no reason they can't be able to) several
possreps have same-named attributes, because that makes sense design-wise, then
user code may have to qualify its access using the possrep name, such as in my
examples in the first email.
2. Another main point of possreps is that in general all of the class' own
methods also shouldn't need to know what the physical representation is, and so
all $.foo or $!foo inside a class, both when referring to the "self" object or
another object of the class, should be able to refer to the attributes of any
possrep and just work. Some methods may wish to talk in terms of one possrep
and some in terms of others, whatever's more natural for them, and it would just
work. Conceptually, all class attributes are virtual.
3. Unless another syntax would work better, I suggest that
possrep-name-qualified attribute references could be formatted as a "foo;"
prefix; for example, $!rect;foo or $!polar;foo if both possreps have a foo, or
that would always work in the general case but plain $!foo would also work when
there's no ambiguity.
4. While in general a sufficiently advanced Parrot can figure out for itself
what physical representation would best do the job, it can be useful for
programmers to explicitly annotate one of their possreps as a recommended
default to use for the physical if the Parrot can't figure out an optimal
solution itself, especially useful for more naive/simple implementations (if no
annotation is done, then a naive implementation may just pick one at random).
5. If there are 3 or more possreps, then the possrep attribute map functions
(the A_from_B I mentioned) only need to exist in enough numbers that if we had a
directed graph where possreps were nodes and the map functions were arcs, then a
path exists between any 2 nodes. You can add more but they aren't necessary.
6. A third main point of possreps is that you should be able to extend a class
with additional possreps, through the normal sub-classing or "subset" mechanism.
At least this would be assuming that we are just performing "specialization by
constraint" (as "subset Foo of Bar where ..." does, example "circle" is subtype
of "ellipse"), and not "specialization by extension" (as a subclass that "adds
attributes" does, example "colored circle is subtype of circle").
For example, you could have an initial class "ellipse" and a subclass "circle"
(every circle is a ellipse), and while an "ellipse" possrep may have 2
attributes for major-axis and minor-axis, the possrep added by "circle" may have
just the 1 radius attribute. So any time you have an Ellipse object where
"$.major == $.minor", you can also refer to $.radius, because that Ellipse then
is also a Circle.
7. Another point is, like with Perl's "subset Foo of ...", if someone does say
"$e = Ellipse.new( :major<2>, :minor<2> )" then "$e.isa(Circle)" would be true
(and "$e.isa(Ellipse)" would also still be true).
Now, conceptually all this is easier to deal with when we just have "value"
types that have immutable objects but it could still work with mutable objects;
then you just have situations where an Ellipse object that was once a Circle no
longer is because you updated just $.minor to be unequal.
8. So a point that raises then is that a savvy Parrot may not use the same
physical representation for every object of the same class, when a subclass may
add a more efficient possrep for just some of its possible objects. Or it could
still use the same physical as the parent class anyway all the time.
9. A subclass can be defined simply to add a possrep but without restricting
the value set; for example if an initial Complex only defines a 'rect'($a1,$a2)
possrep, then a ComplexP subclass could be defined that adds a 'polar'($a3,$a4)
possrep. And then one doesn't have to know the name of the subclass because
they can still say "$n = Complex.new( :a3<4>, :a4<1> )".
10. A subclass can reference the attributes of possreps declared by the parent
class, but the reverse can't happen; all association is just done in the
subclass ... or by users.
11. You can have diamond inheritence in class hierarchies that use possreps,
same as normal classes. For example, you could have these 4 classes in a
diamond: Quadrilateral, Rectangle, Rhombus, Square, each declaring a possrep.
It may be good to disallow the same possrep names used by multiple members or a
hierarchy, or have a disambiguation mechanism as with methods / multis.
12. Subtypes are never required to add possreps, and by default they'd just
work in terms of the parent's possreps.
So in some ways, as Jon suggested, this is a lot like multis.
-- Darren Duncan