Re: Implicit conversions for value subtyping
{ edits: linebreaks inserted in quotes. please keep readers in mind when
quoting. -mod }
On Apr 21, 2:46 pm, "Martin B." <0xCDCDC...@gmx.at> wrote:
On 19.04.2010 14:04, David Barrett-Lennard wrote:
Consider that we implement simple datatypes (i.e. simple "value
types") without virtual functions and all read only functions are
global functions (instead of class member functions). Let single
argument constructors be used to support implicit type conversions.
E.g. to emulate Square value is-a Rect value.
Well. Except that it "isn't" - not in the sense that we are supposed
to(?) understand is-a, namely that everything (interface-wise) you can
*do* with one thing has to be doable with the other thing. (in your
example the interface of Rect implicitly contains the possibility to
change w and h, which Square doesn't.)
I agree that C++ programmers tend to interpret is-a (and sub-typing)
in terms of state machine substitutability (see my second post).
However I think most C++ programmers would agree that every square
*value* is a rectangle *value* (which is what I said).
However, I think your example cleverly captures is-representable-by -
or rather you capture, not that a Square "is-a" Rect, but that a
Square can be (losslessly) converted to a Rect.
It would be a lot simpler if you distinguish between variables and
values. Then just say Square value is a Rectangle value. It's also
clear that a Square variable isn't a Rectangle variable (and vice
versa).
I don't think C++ programmers should assume that any sentence
containing the word "square" in it denotes a variable. E.g. when I
say "a square of area 4" I'm not referring to a variable! I say that
because I think it is a little mischievous for a C++ programmer to
claim it's incorrect to say a square is a rectangle (as if we're only
allowed to talk about variables).
I suggest as a matter of principle that implicit conversions are only
sensible between value types, and they should only be permitted when
they represent alternative encodings of the identical abstract value.
This implies implicit conversions should neither add nor lose
information.
The following uses structs (public member variables) without
suggesting that is necessarily appropriate.
struct Square { int s; };
int side(Square sq) { return sq.s; }
struct Rect
{
Rect(Square s) : w(side(s)), h(side(s)) {}
int w, h;
};
int width(Rect r) { return r.w; }
int height(Rect r) { return r.h; }
int area(Rect r) { return width(r) * height(r); }
void Test()
{
Square s = {10};
int A = area(s);
}
The width, height and area functions defined on rectangle values are
also available for square values, which is just what we need, and
could be viewed as a form of inheritance. (...)
It could. With the right audience. I fear the average listener might
be slightly confused though.
Yes, it seems that C++ programmers reserve the term "inheritance" for
when subclassing is involved.
I think the example shows that there can be value in defining "interface"
functions such that if they only operate on public data there may be
arguments for making them free functions rather than member functions.
That's not the reason for using free functions. See the example
below.
Square inherits functions defined on rectangles but not the
implementation of rectangle (i.e. the member variables). (...)
While I would agree that on a certain conceptual level "inheritance"
seems an appropriate term, I also think that it already has a predefined
meaning that doesn't quite fit your example.
What exactly is the predefined meaning? E.g. is it inheritance of
interface, inheritance of member variables, inheritance of member
functions, or all of these?
Questions:
1) Is this a reasonable technique?
It looks neat and I'm sure there are a few cases where it is very
reasonable. I just wouldn't call it inheritance.
2) Is there a reason why C++ was designed so that const member
functions defeat the implicit conversions on *this?
I'm sure I don't know what you mean by that??
Slightly modified example:
struct Rect
{
Rect(Square s) : w(side(s)), h(side(s)) {}
int area() const { return w*h; }
int w, h;
};
void Test()
{
Square s = {10};
int A = s.area(); // error
}
The compiler won't perform implicit conversions in this case.
--
[ See http://www.gotw.ca/resources/clcm.htm for info about ]
[ comp.lang.c++.moderated. First time posters: Do this! ]