Xref: utzoo comp.lang.eiffel:563 comp.object:707 Path: utzoo!utgpu!jarvis.csri.toronto.edu!rutgers!tut.cis.ohio-state.edu!zaphod.mps.ohio-state.edu!think!barmar From: barmar@think.com (Barry Margolin) Newsgroups: comp.lang.eiffel,comp.object Subject: Re: Real,Complex,Inheritance and Subtyping Message-ID: <32770@news.Think.COM> Date: 10 Jan 90 05:26:12 GMT References: <1526@castle.ed.ac.uk> Sender: news@Think.COM Followup-To: comp.lang.eiffel Organization: Thinking Machines Corporation, Cambridge MA, USA Lines: 62 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