Date: Sat, 20 Sep 2003 08:43:01 +0800
From: Daniel Grimwood <[log in to unmask]>
Yeah ok. It would be nice but I don't know how much effort it would be
for compiler vendors and the standards guys. The main reason I was saying
that we could have multiple parents while disallowing common grandparents
is that it is a reasonably trivial change to the standard. As David said,
this may not be multiple inheritance, but it's a lot more useful than what
the draft has now.
That ["a lot more useful"] is not at all clear. There is a difference
between utility and usefulness. Utility is about capabilities, which
doesn't judge ease of use. Usefulness is a combination of things
including a comprehensible conceptual model. Single-inheritance
(Java, F2K, Smalltalk) is a simple conceptual model.
Single-instance-of-grand*parent multiple inheritance (CommonLisp) is a
slightly more complicated conceptual mode, and the rules imposed on
the DAG are largely intuitive. Let-the-user-decide-(BEWARE!) of C++
is a much more difficult conceptual model. What makes it particularly
tricky is that non-virtual (direct) inheritance is much more efficient
at runtime, and if you get direct inheritance because you *forgot* the
'virtual' keyword and you accidentally end up with multiple
grandparents when only one was intended, you're in for a nasty
debugging session. Granted, a multiple-inheritance-never-shared model
looks conceptually simple, but the never-shared part can complicate
the model pretty quickly.
The basic idea of inheritance is an "IS A" relationship. (Fields,
members, components, whatever the jargon of a particular language, is
a "HAS A" relationship.) The philosophical question is: If something
IS AN Object, isn't it a single Object? Wouldn't it be the equivalent
of a multiple-personality disorder if it were a different Object via
different perspectives?
To make a small case shared inheritance, consider writing a portable
extensible multi-lingual debugger. Consider how it represents types
of a particular vendor's language, say Digital's F90 for Alpha/Tru64.
(OK, I wrote such a debugger... and this is somewhat of a legacy
platform now, so I don't think I'll offend anybody.) Consider (using
F77's terminology) INTEGER*4. I claim the following "IS A" statements
are valid (read INTEGER*4 as bound to Digital Alpha/Tru64 F90):
-- INTEGER*4 IS A Fortran integeral type (so is integer*2)
IS A Fortran non-complex type (so is real*4)
IS A Fortran numeric type (so is complex)
IS A Fortran type (so is character)
!! IS A language type (so are C types)
!! IS A type
!! IS AN object
-- INTEGER*4 IS AN integral type
IS A rational type (so are ratios)
IS A real type (so are
IS A numeric type
!! IS AN abstract type
!! IS A type
!! IS AN object
-- INTEGER*4 IS A 32 bit fixed-size integer type (so is 16 bit)
IS A fixed-size type (so is ieee floats)
!! IS A manifest type (so is variable)
!! IS A type
!! IS AN object
-- INTEGER*4 IS A little-endian type
!! IS A manifest type (so is big endian)
!! IS A type
!! IS AN object
The statements with a double !! show the higher level categories I
decided on for organization. The first is the language perspective,
the second is the abstract perspective, and the third&fourth are the
representaiton perspective(s). They all participate in what an
INTEGER*4 "IS" and how it behaves. In the end, it IS A type, no
matter which of the four direct ways through the DAG you go, or the
dozens of other ways (e.g., A fortran non-complex type is also an
(abstract) real type, just to name one).
Unfortunately for me, this uncovered several bugs in more than one C++
compiler. The workaround for one of those bugs was to delare more of
the inheritances to be virtual than technically needed to be!
|