substitution principle

8.21: adda/oop/type/substitution principle:
. when a parameter is type rectangle,
then it can be assigned any rectangle
including a square;
because, a square is rectangular .
. classic oop has had a problem with that,
so, how do we sort out our subtypes
from this jumble of subclass confusion?
. the solution I've come up with
is known as Changing The Language:
ie, rather than assume a type.tag is constant;
we assert that related types
are expected to have a common surtype;
eg, for a var constrained to Number.type,
it will have a constant surtype.tag;
but, it will also have a modifiable subtype.tag,
that can vary within {N,Z,Q,R,C}
(unsigned, int, quotient, real, complex).
. a var constraint can be a subtype too:
eg, for a var constrained to Real,
it can only vary in {N,Z,Q,R};
ie, the subtypes whose domains are
subsets of Real's domain .
. and, as usual for non-oop,
if a var is constrained to a definite type, such as float32,
then both the surtype and subtype
are going to be constant
(hence the obj will be untagged);
but, since the surtype is Number,
and float32 is understood to be a subtype of Real,
you can ask for (float32 + int)
and multi-dispatching will still work .]
. in order to be a subtype of rectangle,
an object that is tagged as being a square
has got to be re-taggable as non-square
in the event that the rectangle interface
asks it to modify itself;
ie, a type that inherits from rectangle
and then adds the constraint
that it be a square too -- forever --
has decided to nix support for type compatability,
which contradicts the idea of inheritance .
. to be a subtype (ie, support type compatability)
the inheritance needs to work like this:
my subtype named square
has the properties of the inherited rectangle
but includes the constraint width = height .
. if you ask me to break that constraint,
then I'll re-type.tag myself as a rectangle
(rectangular but not square).
[11.9: corrollary:
. if a var is constrained to be a square,
then the only rectangle it can be assigned to
is an unmodifiable one;
being assigned to a modifiable rectangle,
could potentially violate the type constraint,
and should result in a compile-time warning .
. this isn't a fatal error though;
because, the user could expect that
squares will grow in only a square way,
-- as would be the case for doublemy(rectangle) --
or the user may want to handle the exception
by trying another algorithm;
therefore, the warning should remind the users,
that they appear to be depending on
either having exceptions handle
the type.constraint.error,
or having the rectangle operation
not violate a square's subtype.constraint .]