Re: object possible representations (was Re: r28523 - ...)
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 anyway: 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 class
Re: object possible representations (was Re: r28523 - ...)
Some further thoughts: Essentially, this could be done as an extension of the versioning system. The difference between "possrep" versioning and normal versioning would lie in the means by which the possrep dimension would be resolved if not specified. Namely, the compiler would make the decision based on the natures of the various classes and the preferences of the various function calls. To illustrate, let's say that we have two implementations for Complex: one that's optimized for rectilinear coordinates, and another that's optimized for polar coordinates. class Complex:opt { ... } class Complex:opt { ... } ...where "opt" is short for "optimized implementation". Both implementations of Complex would be able to use rectilinear and polar accessors; indeed, the assumption is that both are capable of handling the exact same interfaces, differing only in terms of how well they handle various aspects thereof. A routine's signature could then include a request for one or the other - say, something like: sub foo(Complex:opt) { ... } This would not _require_ that a Complex:opt be provided; only that a Complex be provided. But if I were to say "my Complex $x;", followed by a large number of "foo $x" calls, the compiler might choose to implement $x as a Complex:opt. More radically, the sig might be able to provide a priority number as well as an "option name": e.g., 0 for "this is just a suggestion"; 1 for "it's strongly recommended that you supply this implementation"; and 2 for "do whatever it takes to supply this implementation". So: sub foo(Complex:opt) { ... } sub bar(Complex:opt) { ... } ...Would mean that if you try to hand foo a Complex:opt, foo will coerce it into a Complex:opt before using it; whereas bar would accept it as is. But if the compiler sees that a lot of bar $x calls are coming up, and $x is currently a Complex:opt (or it's at the declarator and no implementation preference has been given), it might convert $x to a Complex:opt before it gets to the first of them, just to smooth the way. -- Jonathan "Dataweaver" Lang
Re: object possible representations (was Re: r28523 - ...)
Darren Duncan wrote: > Jon Lang wrote: >> I'm not sure that I feel comfortable locking C into >> rectilinear coordinates as its internal storage method, as there will >> be cases where the code operates more smoothly if you're using polar >> coordinates to store the numbers: we should leave the inner workings >> up to the Parrots to decide. But whichever approach gets used, if >> either component is NaN, then the complex number should also be NaN. > > I'm not sure if the idea is applicable to Perl 6 because Perl 6 already has > an alternative but ... > > One of the features of my Muldis D language is called possreps (possible > representations) where you may define more than one alternative set of > attributes for a data type (and if more than one, you also define functions > to map between each attribute set) and then the implementation can choose > for itself which of those representations (or it can pick yet another one of > its own) is the actual one used physically behind the scenes and which is > virtual, and the user could use either as if it were the real one. > > What Perl 6 could do with this concept is for example it can define for some > classes multiple possible object attribute sets, so users know they can use > any of those, and then each Perl 6 implementation can choose what to do > natively. > > So the Perl 6 spec can and should enumerate the various reasonable > alternative sets of attributes that a Complex object could have, and the > Parrots can choose which to use internally, or could use more than one on a > case-by-case basis. > > Note that ideally this would be a feature that user-defined classes can use, > and not just language built-in ones. This sounds a bit like how the "multi" keyword applies to Perl 6 routines to define several routines that share one name. Perhaps there's a way to say "multi class", letting you define several "classes" that are different implementations of the same thing, with each class definition within the multi class being a "possrep". I'm not exactly sure how this would work (you'd need some way to distinguish between the different class definitions, much like multi routines each have a unique long name even though they share the same short name); but it strikes me as being more in keeping with the nature of Perl than nesting several possrep blocks within a single class definition. Perhaps a multi class would involve some sort of implicit version control, with each class definition being given a slightly different version? (Do we still have proto routines to go along with multi routines? If so, you could use a proto class to define common features shared by all of the implementations, such as identifying which roles the multi class does.) Whatever mechanism gets established, the basics would involve being able to establish more than one possible implementation for a class, combined with an ability to identify each implementation's relative strengths and weaknesses so that the compiler has a way to choose which one to use. > Now in Muldis D this system is strict and requires that one can round-trip > between any 2 possreps and have identical attribute values to what one > started with, so the Complex example where conversion would by nature be > approximate wouldn't work there; but in Perl or a language where > nonidentical round-trips are allowed, this may work for Complex too. But > then the implementation would have to always use the same physical > representation for all objects of the same class, or else it wouldn't always > DWIM when some one tries an exact equality test with objects. If only there was a way for Perl to track exact values for irrational numbers like it does for rationals, rather than trying to approximate them with Num; then one _could_ set up a round trip between rectilinear and polar coordinates that preserves the original values (in theory, at least; you'd still have to figure out how to address the "0 = 2 * pi" problem). -- Jonathan "Dataweaver" Lang
object possible representations (was Re: r28523 - ...)
Jon Lang wrote: On Wed, Sep 30, 2009 at 11:58 PM, wrote: +C is an immutable type. Each C object stores two numbers, +the real and imaginary part. For all practical purposes a C with +a C in real or imaginary part may be considered a C itself (and +C<(NaN + 1i) ~~ NaN> is C). I'm not sure that I feel comfortable locking C into rectilinear coordinates as its internal storage method, as there will be cases where the code operates more smoothly if you're using polar coordinates to store the numbers: we should leave the inner workings up to the Parrots to decide. But whichever approach gets used, if either component is NaN, then the complex number should also be NaN. I'm not sure if the idea is applicable to Perl 6 because Perl 6 already has an alternative but ... One of the features of my Muldis D language is called possreps (possible representations) where you may define more than one alternative set of attributes for a data type (and if more than one, you also define functions to map between each attribute set) and then the implementation can choose for itself which of those representations (or it can pick yet another one of its own) is the actual one used physically behind the scenes and which is virtual, and the user could use either as if it were the real one. What Perl 6 could do with this concept is for example it can define for some classes multiple possible object attribute sets, so users know they can use any of those, and then each Perl 6 implementation can choose what to do natively. So the Perl 6 spec can and should enumerate the various reasonable alternative sets of attributes that a Complex object could have, and the Parrots can choose which to use internally, or could use more than one on a case-by-case basis. Note that ideally this would be a feature that user-defined classes can use, and not just language built-in ones. Now that I think about it, one way this could work within Perl 6's existing features is that Complex could be a role and each of the possible representations could be a class that does that role. On the other hand ... Perhaps how my actual proposal could be realized is as sugar in the language where one could write say: class A { possrep B { has $c; has $d; } possrep E { has $f; has $g; } my submethod E_from_B ($c, $d) { } my submethod B_from_E ($f, $g) { } } Then users could say for example: my A $x = A.B.new( :c<1>, :d<2> ); my A $y = A.E.new( :f<4>, :g<5> ); my $c = $y.B.c; my $f = $x.E.f; Of course, actual details or syntax could be different, but I think this general idea would be useful. Note that in my actual proposal, B and E are *not* classes so doing "my E $foo" is invalid; the only class here is A. Now Perl 6 may choose to design differently. Now in Muldis D this system is strict and requires that one can round-trip between any 2 possreps and have identical attribute values to what one started with, so the Complex example where conversion would by nature be approximate wouldn't work there; but in Perl or a language where nonidentical round-trips are allowed, this may work for Complex too. But then the implementation would have to always use the same physical representation for all objects of the same class, or else it wouldn't always DWIM when some one tries an exact equality test with objects. -- Darren Duncan