Nick --

I've been thinking of it like this:

  class int isa intlike; # and isa value or whatever
  class Int isa intlike; # and isa Object or whatever

  class num isa numlike; # and isa value or whatever
  class Num isa numlike; # and isa Object or whatever

  ...

  class Scalar isa intlike, numlike, ...; # and isa Object or whatever

The *like classes are placeholder (interface) classes that capture
the ability to *treat as* (as opposed to *really is*). And (importantly
IMO) the *like classes capture the aspects of foo and Foo that
are the same, leaving the foo and Foo classes to capture the
differences.

 - - - - - - - - - - - - - - - - - - - - - -

A different way to handle Scalar would be to have Perl 6 allow
mutating objects (type changes). Scalar could be a superclass
of Int and Num, but it could be abstract (no instances allowed).
Values would be only of concrete types (e.g. Int, Num, Str). That
isn't very tricky, until you try to do

    my $x = "5";
    $x += 37;

Is $x the same object as it was before, but with a different internal
state, or is it now a completely different object (since its type
presumably changed to Int from Str)?

I'm not as comfortable with this, I have to admit. I like a single Scalar
class that has magical internal state and presents various "facets"
to the outside world (Int, Num, Str, ...). The magical internal state
can do things like maintain Int and Str values in parallel if it wishes
(which would be a strange thing for Int to do by itself, IMO).

 - - - - - - - - - - - - - - - - - - - - - - - -

FWIW, I think Circle is a predicate on the set of Ellipses, so I'd say
Circle isa Ellipse. If I were using Eiffel, I'd use renaming and
overriding so that you could query the semimajor and semiminor
axes and radius, and get the same number in all three cases.
And, if you are working with a value that isa Circle, you may not
*set* the semimajor and semiminor axes (you have to set the
radius). Of course, this makes things ugly when you have a Circle
in an Ellipse variable. You'd like to take the fact that something
is an Ellipse to mean that you *can* set the axes separately,
since that is an Ellipse kind of thing to do. This smacks of an
argument for Ellipse and Circle being peers -- subclasses of
some other abstract helper class.

Or, to truly simplify, don't have a Circle class at all. Have an isCircle
predicate on Ellipse, which matches the mathematical case nicely.
Being able to do C<my $foo = new Circle 137> and get back an
appropriate ellipse would still be nice, though.

I think the trouble comes from the fact that there are two kinds of
Circle that come up: Ellipse-in-general-but-Circle-right-now (loose,
or behavioral) and Circle-we-want-to-treat-as-Ellipse-sometimes
(strict, classical). You could definitely make an Ellipse class that
had an isCircle method, a radius-based constructor, and
getRadius and setRadius methods, and the only time it would let
you down is if you didn't check isCircle before calling getRadius,
because it would throw an exception (since there is no single
radius for a not isCircle Ellipse). It means your class is really
EllipseOrCircle, I guess.

For the strict case above, you would have to have though
ahead enough to have the Ellipse-like 'get' methods in one
place and teh Ellipse-like 'set' methods elsewhere. Circle
could inherit from the EllipseGettable but not EllipseSettable
(since you can ask for, but not set the semi axes).


Regards,

-- Gregor Purdy




Nicholas Clark <[EMAIL PROTECTED]>
03/15/2003 06:48 PM

 
        To:     "[EMAIL PROTECTED]" <[EMAIL PROTECTED]>
        cc: 
        Subject:        Re: A6: Complex Parameter Types


There seems to be some confusion about which way up the world is.

On Tue, Mar 11, 2003 at 01:25:41PM +1100, Damian Conway wrote:
> Which in turn is because:
> 
>                not Scalar.isa(int)

On Thu, Mar 13, 2003 at 11:55:06AM -0800, Larry Wall wrote:
> On Thu, Mar 13, 2003 at 11:31:30AM -0800, Austin Hastings wrote:
> : "Everyone Knows" that an Int is a Scalar, and therefore a sub that has
> : a Scalar parameter can safely be passed an Int. This is normal.

> I don't see a problem.  Scalar == Int|Num|Str|Ref, so Scalar.isa("Int").
> 
> Larry

On Thu, Mar 13, 2003 at 12:00:54PM -0800, Paul wrote:
> > I don't see a problem.  Scalar == Int|Num|Str|Ref, so
> > Scalar.isa("Int").
> 
> Scalar.isa("Int") && Int.isa("Scalar") ????

This term "subtyping" I didn't know:

On Fri, Mar 14, 2003 at 10:46:31AM -0800, Larry Wall wrote:

> Well, I'm using the terms type and class pretty much interchangeably
> there, so don't put too much weight on that.  But Perl 6 may well
> distinguish classes from types.  Classical classes can only add
> capabilities when you derive (yes, you can redefine methods to do less,
> but the interface is still there).  When I think of types, I'm thinking
> of parameterizing a class with some constraints.  In the Ada world,
> that's called "subtyping".  Whether these contraints are mathematical
> ("must be an even number") or structural ("must have dimensions
> (3,3,3)"), they still cut down on the allowed set of values for the
> base type.

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.

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?

This reminds me of a conundrum that was explained to me - sub-classing
geometry:

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.

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.

Nicholas Clark



Reply via email to