[comp.lang.eiffel] Real,Complex,Inheritance and Subtyping

db@lfcs.ed.ac.uk (Dave Berry) (01/10/90)

The class Complex can be defined using two attributes of class Real.  Are
there any languages in which it is then possible to make Real a subtype of
Complex?  Is this an example when subtyping should be separated from
inheritance?

Are there any better ways to do this?  Should Real and Complex both
be subtypes of class Numeric, with user-defined coercions?  Are there
any languages in which it is possible to ensure that  Real + Real  calls
Real.+ and any combination of Reals and Complexes calls Complex.+ , without
having to define all cases explicitly?

Aside: the standard OO response is that the function called depends on
the first argument of the function call/message.  That's always seemed
inadequate for addition and similar operations.

This has been a question that's puzzled me for some time.

Dave Berry, Laboratory for Foundations      db%lfcs.ed.ac.uk@nsfnet-relay.ac.uk
    of Computer Science, Edinburgh Uni.	    <Atlantic Ocean>!mcvax!ukc!lfcs!db

"leIsANewEntertainment:GuerillaWarStruggleIsANewEntertainment:GuerillaWarStrug"

jlg@lambda.UUCP (Jim Giles) (01/10/90)

From article <1526@castle.ed.ac.uk>, by db@lfcs.ed.ac.uk (Dave Berry):
> [...]                                                       Are there
> any languages in which it is possible to ensure that  Real + Real  calls
> Real.+ and any combination of Reals and Complexes calls Complex.+ , without
> having to define all cases explicitly?

NEMESIS is an experimental language here which can do that.  Although
not explicitly intended to be Object Oriented, NEMESIS has several
features which make generic funcions (at least) easier to write and use.

The declaration of complex plus '+' might look something like this:

   Class Number is (integer, real, complex)

   Infix commutative associative operator '+' is
   Complex inline function Complex_Plus(Number::x, Complex::y)
      Complex_Plus.real = complex(x).real + y.real
      Complex_Plus.imag = complex(x).imag + y.imag
   End Complex_Plus

Since NEMESIS is based (loosely) on Fortran, the declaration syntax
for variables and functions puts the typename first.  Class isn't
like class in OOP, it is just a way of giving a name to a set of data
types so that generic programs can be coded more simply.  Note that
the degree to which the function is polymorphic is bounded since
only those types in the definition of Number are allowed as operands.
This may sometimes be useful.  If you disagree, then the first
operand (x) could have been declared as Object instead of Number
and then any type operand would be permitted.  There is a certain danger
in this because Complex(x) must also accept whatever type is passed,
and the result must have .real and .imag components, and those components
must be able to be added to reals.

Note that the operator is declared as commutative so that the non-complex
operand will always be matched to the first argument to the function.
If both operands are complex, the order of operands is irrelevant (the
compiler assumes this).  The complex(x) function is also generic and
is the no-op if x is already complex.

The function will be expanded inline (provided the operand types are known
at compile time and that the module containing the complex '+' definition
is available to the compiler).  If late binding must occur, the function
will be called as an external.

The above is not actually the declaration of Complex in NEMESIS since
there are more Number types than those given and there are more attributes
that operators and functions can be given.  Still, this is the bare
bones of the matter.

J. Giles

barmar@think.com (Barry Margolin) (01/10/90)

In article <1526@castle.ed.ac.uk> db@lfcs.ed.ac.uk (Dave Berry) writes:
>The class Complex can be defined using two attributes of class Real.  Are
>there any languages in which it is then possible to make Real a subtype of
>Complex?  Is this an example when subtyping should be separated from
>inheritance?

If anyone were to try such a thing, I'd think they were doing it backwards.
Types in programming languages generally model sets in mathematics, and
real numbers are a subset of complex numbers, so it would make more sense
for the type Real to be a subtype of Complex.  Reals are just those
Complexes whose imaginary part is 0.

>Are there any better ways to do this?  Should Real and Complex both
>be subtypes of class Numeric, with user-defined coercions?  Are there
>any languages in which it is possible to ensure that  Real + Real  calls
>Real.+ and any combination of Reals and Complexes calls Complex.+ , without
>having to define all cases explicitly?

It's pretty easy in CLOS (Common Lisp Object System):

(defmethod + ((arg1 real) (arg2 real))
  (Real.+ arg1 arg2))

(defmethod + ((arg1 complex) (arg2 complex))
  (Complex.+ arg1 arg2))

... other special cases go here ...

;;; General case
(defmethod + ((arg1 number) (arg2 number))
  (General-+ arg1 arg2))

I didn't implement quite what you said, because it seems to me that
Complex.+ would be best implemented as a function that expects its
arguments to be already coerced to complex, so that it could take advantage
of a known representation.  General-+ would do appropriate coercion and
then call + with the coerced arguments.  Alternatively, Complex.+ could be
implemented in terms of Real-part and Imaginary-part generic functions, and
Real.Imaginary-part would always return 0.0, and it's equivalent to
General-+.  However, when the type lattice gets more complex (throw in
Integer, Rational, Integer-Complex, Rational-Complex, Real-Complex (the
latter three are Complexes whose components are the specified type)) it
becomes more useful to have a variant that does the coercion.

>Aside: the standard OO response is that the function called depends on
>the first argument of the function call/message.  That's always seemed
>inadequate for addition and similar operations.

CLOS permits methods to be selected based on all the required arguments.
Ada overloading also permits this.

The reason that many OO languages don't do this is that it has long been
assumed that a type is a combination of a representation and a set of
methods, so methods are associated with a particular type.  Implementors
like this as well because they can simply map from the type of an argument
to a method table.  But, as you point out, this view is often inadequate.

--
Barry Margolin, Thinking Machines Corp.

barmar@think.com
{uunet,harvard}!think!barmar

macrakis@marat.osf.fr (Stavros Macrakis) (01/16/90)

In article <32770@news.Think.COM>, barmar@think.com (Barry Margolin) writes:
> In article <1526@castle.ed.ac.uk> db@lfcs.ed.ac.uk (Dave Berry) writes:
> >The class Complex can be defined using two attributes of class Real.  Are
> >there any languages in which it is then possible to make Real a subtype of
> >Complex?  Is this an example when subtyping should be separated from
> >inheritance?
> 
> If anyone were to try such a thing, I'd think they were doing it backwards.
> Types in programming languages generally model sets in mathematics, and
> real numbers are a subset of complex numbers, so it would make more sense
> for the type Real to be a subtype of Complex.  Reals are just those
> Complexes whose imaginary part is 0.

The relationship between the complex numbers and the reals can indeed be seen
from two different perspectives: one, the reals are a special case (a subset,
if you like) of the complex; the other, the complex are constructed from the
reals.  Neither is more correct, either in mathematics or in programming.

Indeed, each approach has its strengths and its weaknesses.

If you take the "subset" approach, then perhaps you should model the complexes
as a subset of the quaternions, or of the square matrices, etc. etc.

If you take the "construction" approach, perhaps you should model complexes
in polar form, or as two infinite bit-vectors, or as a pair of integer/fraction
parts.

Both are incomplete views.  In particular, it's really not the "subset"
property that matters, but the "substructure" property.  (there's the classic
article "Why Data Types are Not Sets" which appeared in Sigplan Notices about
12 years ago which goes into more detail-- sorry, I don't have the reference).

	-s