> I'm not sure if it helps people understand why I'm confused by explaining > my background, but I've done exactly zero computer science, and have come > to whatever (mis)understanding of OO I have by using C++ (and then perl). > I've never used Java, but I'm aware that it has a concept of "interfaces" > that can cleanly fulfil most of what C++ programmers end up using multiple > inheritance for.
(But not all of it; eg. design-by-policy) > Back to perl: > > I admit that I think of Scalar as being something that conceptually > multiply inherits from String, Num, Int and "other" (ref), because a scalar > can be any of these things as it feels necessary. Being from somewhat a C++ > background (oh, and knowing how SVs work in perl5's source), I don't really > feel that the tree goes the other way, with Scalar at the top. I don't > expect Int to have a (in perl5-speak) .= method, but if Int inherits from > Scalar, it's going to have to, isn't it? Good observation. I agree. The problem is that there's a Liskov substitution that's tripping people up. An Int can be given to a Scalar argument, so it must be a subclass. It may be that Scalar is unrelated, inheritance-wise, to the four basic types. Rather, it aggregates and delegates, and provides conversions to and from them. > Presumably a Circle class has an attribute radius, which can be set and > retrieved. And Ellipse has two, semi-major axis and semi-minor axis. > A circle is an ellipse where the semi-major and semi-minor axes are equal. > > So, if you implement Circle as a subclass of Ellipse this is fine - Circle > provides the radius methods, so there's no way an Ellipse can have one called > on it. Good. And if you call Ellipse's semi-major axis method on a Circle > you get back the same value as radius (or semi-minor axis) > > But what happens if take a Circle (isa Ellipse) and try to set the semi-major > axis to a value that differs from the semi-minor axis? (I don't know. It > violates something as I understand it) > > > Conversely, if you implement Ellipse as a subclass of Circle, this problem is > solved. There are no semi-major or semi-minor axes methods, so no chance of > going wrong there. But as Ellipse isa Circle, it will inherit Circle's radius > method. What should it return the radius of an Ellipse? (I don't know) > > I don't know the answer to which way up they go. As I understand it, there > is no right answer. Well, I think this is one of those subtyping things Larry is talking about (Circle doesn't I<extend> Ellipse, it puts a constraint on it). But in the most generic world, I would not subclass either. I might implement Circle with an Ellipse (spelled C<private> in C++), but their interfaces are incompatible as you've described. You can't use an Ellipse as a Circle, because it has no radius, and you can't go the other way around, because Circle's can't change their semi-major axis. I know this is just a silly example, but in my experience, a common design mistake is to use inheritance too liberally. This is a good demonstration of that. Circle and Ellipse should be siblings in this family (perhaps derived from Shape). > Likewise I'm not convinced about which way round the scalar types heirachy > goes in perl6. I like it to be both ways up at the same time. > (in the same universe please) > Then again, this week is the subroutines apocalypse, not the objects > apocalypse, so hopefully all will become clear in a subsequent this week. The more I think about this design, the more I like the solution of no inheritance relation between them. I would implement Scalar as a proxy to whatever lies underneath, stored as references (perhaps) so changes would be reflected back. class Scalar { submethod BUILD($.num is rw) { } submethod BUILD($.str is rw) { } submethod BUILD($.ref is rw) { } method infix:+= ($self: $rhs) { $.num += $rhs.num; $.str = $.ref = Undef; $self; } multi infix:as(Scalar $self, Class(Num) $class) returns(Num) is rw { return my $x is Proxy( for => $.num, STORE => { $.str = $.ref = Undef; $num = $_ }) } # Using the multimethod, um, method for auto conversion # ... has Num|Undef $.num; has Str|Undef $.str; has Ref|Undef $.ref; }; Or something like that, maybe. Luke