Topic: const inheritance?


Author: fenster@age.cs.columbia.edu (Sam Fenster)
Date: 16 Jan 1995 16:01:50 GMT
Raw View
> I've been thinking about an extension to C++ that I'd like to hear comments
> on. The idea is "const inheritance".  In this extension, a derived class
> could specify that it derives in a "const" fashion from a base class,
> meaning that it only inherits the "const" methods from the base class.
> ...
> To make this work in C++, a pointer or reference to a circle could be
> automatically converted to a const pointer to ellipse, but not to a mutable
> pointer to ellipse.
>
> Any comments?

Yes: I agree completely.  In general, "const foo" should be considered a base
class of "foo".  It satisfies the Liskov substitution principle of subtypes,
which is that a type can be used anywhere its supertypes can be used.  A "foo"
can do anything a "const foo" can do.  And you may want to inherit from "const
foo", not from "foo".

Without this capability, I end up with ugly designs where I have to split my
class design into two classes, "class Const_Foo" and "class Foo: public
Const_Foo", with all the const operations in the former, just so I can derive
classes that inherit Foo's logical state but have constraints on changing it.
This design also forces me to use redundant constructs like "void bar (const
Const_Foo&)":

   class Const_Matrix_2x2 { // ...
      Const_Matrix_2x2 transpose () const;
   };
   class Matrix_2x2: public Const_Matrix_2x2 { // ...
      virtual const Const_Matrix_2x2 &operator *= (const Const_Matrix_2x2 &);
   };
   class Const_Rotation_2x2: public Const_Matrix_2x2 { // ...
      double angle () const;
   };
   class Rotation_2x2: public Const_Rotation_2x2 { // ...
      // *= with an arbitrary Matrix_2x2 is not allowed:
      virtual const Const_Rotation_2x2 &operator *=
         (const Const_Rotation_2x2 &);
   };

Whereas, if C++ considered const Foo a base class of Foo, the design would be
concise and natural:

   class Matrix_2x2 { // ...
      Matrix_2x2 transpose () const;
      virtual const Matrix_2x2 &operator *= (const Matrix_2x2 &);
   };
   class Rotation_2x2: public const Matrix_2x2 { // ...
      double angle () const;
      // *= with an arbitrary Matrix_2x2 is non-const, so not inherited!
      virtual const Rotation_2x2 &operator *= (const Rotation_2x2 &);
   };

I think this is a natural extension to the class semantics that is necessary
to allow non-ugly, non-redundant, non-error-prone design.  It is especially
important when I don't own the class I'm deriving from.




Author: maxtal@physics.su.OZ.AU (John Max Skaller)
Date: Fri, 20 Jan 1995 10:06:25 GMT
Raw View
In article <9501921.20745@mulga.cs.mu.OZ.AU> fjh@munta.cs.mu.OZ.AU (Fergus Henderson) writes:
>
>What you said about covariance and contravariance is correct if you
>talk about "write-only" rather than "non-const".

 Yes, that may be right.

 I think, in fact, I am considering the distinction
between the type of something in an R context (rvalue/value used)
as opposed to an L context (lvalue/address used).

 Conider the expression

 (c?b:d)

where d is a D*, b is a B* and D is derived from B. In an R context,
the type of the expression is B*, in an L context, the type would
_have_ to be D*. In fact, C++ solves this problem by simply
banning such expressions in L contexts (the type of the last
two arguments have to be the same). A similar issue
arises when b is type "long" and d is type "short"
(and both are lvalues).

The point here is that there exist expressions whose type depends on
the context in which the expression is used. It is trivial
to extend this observation to _all_ types. For example:

 int x;
 x = x;

In this case, the RHS has type "int" and the LHS has type "int&".
The types are distinct and context dependent. Note that

 (c?b:d) +=1;

is interesting because it is a read/modify/write operation.


--
        JOHN (MAX) SKALLER,         INTERNET:maxtal@suphys.physics.su.oz.au
 Maxtal Pty Ltd,
        81A Glebe Point Rd, GLEBE   Mem: SA IT/9/22,SC22/WG21
        NSW 2037, AUSTRALIA     Phone: 61-2-566-2189




Author: jason@cygnus.com (Jason Merrill)
Date: Sat, 14 Jan 1995 03:45:10 GMT
Raw View
It seems to me that the circle/ellipse design problem is easily resolved
this way: A circle is an ellipse such that the foci are at the same point.
So:

class ellipse
{
  virtual void move_foci1 (x, y) {...}
  virtual void move_voci2 (x, y) {...}
};

class circle: public ellipse
{
  void move_center (x, y) {...}
  void move_foci1 (x, y) { move_center (x, y); }
  void move_foci2 (x, y) { move_center (x, y); }
};

Jason




Author: maxtal@physics.su.OZ.AU (John Max Skaller)
Date: Sat, 14 Jan 1995 10:43:19 GMT
Raw View
In article <HOUGH.95Jan13174606@fermat.aai.com> hough@aai.com writes:
>
>I've been thinking about an extension to C++ that I'd like to hear
>comments on. The idea is "const inheritance".  In this extension,
>a derived class could specify that it derives in a "const" fashion
>from a base class, meaning that it only inherits the "const" methods
>from the base class.
>
>For example, in the classic  does-circle-derive-from-ellipse-or-does
>ellipse-derive-from-circle design problem, neither
>circle inheriting from ellipse nor ellipse inheriting from circle work.
>If a circle is-a ellipse, then modifying a ellipse that happens to
>be a circle breaks the circle.

 I dont think it works. The reason is that I suspect
that mutation is contravariant while access is covariant.

 class ConstEllipse { .. }
 class ConstCircle
  : public virtual ConstEllipse { .. getRadius() .. }

 class Circle
  : public virtual ConstCircle { .. setRadius ...}
 class Ellipse
  : public virtual Circle, public virtual ConstEllipse { ..}

  ConstEllipse
  / \
 ConstCircle Ellipse
  \ /
  Circle

That is, the problem is that a ConstCircle "isa" ConstEllipse,
whereas a non-const Ellipse "isa" non-const Circle. That is,
accessors and mutators vary in opposite directions.
--
        JOHN (MAX) SKALLER,         INTERNET:maxtal@suphys.physics.su.oz.au
 Maxtal Pty Ltd,
        81A Glebe Point Rd, GLEBE   Mem: SA IT/9/22,SC22/WG21
        NSW 2037, AUSTRALIA     Phone: 61-2-566-2189




Author: kevlin@wslint.demon.co.uk (Kevlin Henney)
Date: Mon, 16 Jan 1995 13:28:23 +0000
Raw View
In article <HOUGH.95Jan13174606@fermat.aai.com> hough@aai.com "Al Hough" writes:

>I've been thinking about an extension to C++ that I'd like to hear
>comments on. The idea is "const inheritance".  In this extension,
>a derived class could specify that it derives in a "const" fashion
>from a base class, meaning that it only inherits the "const" methods
>from the base class.
>
>The purpose of this is to allow a style of class hierarchy design
>in which subclasses restrict the range of values allowed by base classes.

Methodologically this kind of programming should not be encouraged as it
breaks with subtype substitutability, and so adding language support is
IMHO the wrong direction to go.

>For example, in the classic  does-circle-derive-from-ellipse-or-does
>ellipse-derive-from-circle design problem, neither
>circle inheriting from ellipse nor ellipse inheriting from circle work.
>If a circle is-a ellipse, then modifying a ellipse that happens to
>be a circle breaks the circle.

You're on the right track when suggesting const inheritance, but a
better approach might be to reanalyse the problem. A circle _is_ an
ellipse, so long as certain properties are immutable:

   RescalableEllipse (maintains same shape thru whole life)
    ^          ^
    |          |
 Circle    ReshapeableEllipse (major and minor axis ratio may change)

For some applications this is the appropriate partitioning, whereas for
others circularity is used differently, and so the hierarchy can be
collapsed into a single ellipse class with an IsCircle predicate. Or if
you use a value based functional style, objects are immutable and so
a circle can safely aubtype an ellipse as properties are only changeable
by rebinding.

Like I say, it often depends on the problem domain and no extra language
support is required.

Hope this helps.

+---------------------------+-------------------------------------------+
| Kevlin A P Henney         | Human vs Machine Intelligence:            |
| kevlin@wslint.demon.co.uk | Humans can wreck a nice beach more easily |
| Westinghouse Systems Ltd  |                                           |
+---------------------------+-------------------------------------------+