Subtyping is supported in C++ only to
a very limited extent.
Function subtypes are completely absent.
However, class subtypes due to derivation by
inheritance may be employed.
Also, built-in conversions are provided,
some of which are in accordance with the subtyping
requirements,
and some of which, unfortunately,
violate the subtyping requirements.
Built-in conversions exist, for example,
between double and int, in both ways.
However, whereas the conversion from int to double
is safe, the other way around may cause loss of
information by truncation.
The type system sketched in slide 9-c-subtypes
is quite easily mapped to a C++ context.
For example, we may mimic the functions S
and twice as given in slide 9-ex-subtypes
in C++ as:
int S(int x) { return x+1; }
int twice(int f(int), int y) { return f(f(y)); }
int twice_S(int y) { return twice(S,y); }
Nevertheless, the type system of C++ imposes
some severe restrictions.
For example, functions may not be returned
as a value from functions.
(Although we may provide a workaround, when we employ
the function for objects.)
The absence of function subtyping becomes clear
when, for example, we call the function twice
with the function SD, which is defined as:
According to the subtyping rules and in accordance
with the substitutability requirement,
we employ SD whenever we may employ S.
But not so in C++.
We run into similar limitations when we try
to refine an object class descriptions following
the object subtype refinement rules.
class P {
\fbox{P}
public:
P() { _self = 0; }
virtual P* self() {
return _self?_self->self():this;
}
virtual void attach(C* p) {
_self = p;
}
private:
P* _self;
};
class C : public P {
Suppose we have a parent class P which offers
the member functions self and attach,
as in slide 9-cc-sub.
The meaning of the function self is that
it de-references the _self variable if
it is non-zero and delivers this otherwise.
(See section hush for an example of its use.)
The function attach may be used to connect an
instance of C to the _self variable.
The class C in its turn inherits from P
and redefines self and attach.
Syntactically, both refinements are allowed,
due to the function subtype refinements rules.
The function self is redefined to deliver
a more tightly specified result,
and the attach function is allowed to take a wider
range of arguments.
In the AT&T 3.0 version of C++,
both redefinitions are considered illegal.
However, in the ANSI/ISO standard of C++,
redefining a member function to deliver
a subtype (that is, derived class) pointer will be allowed.
Redefining attach, as has been done for C
is probably not a wise thing to do,
since it changes the semantics of attach
as defined for the parent class P.
In effect, it allows us to write
instead of
, for and .
Nevertheless, from a type theoretical perspective,
there seem to be no grounds for forbidding it.