Topic: hole in C++ ?


Author: "Jaewoo Kim" <kizoo@esther.donga.ac.kr>
Date: 1998/09/08
Raw View
Valentin Bonnard @L(0!) <35F401C7.424A@pratique.fr> 8^=CAv?!<-
@[<:GO?4=@4O4Y...
>Jaewoo Kim <kizoo@esther.donga.ac.kr> writes:
>
>> The resulting difficulty is not just for C++, but for nearly all
>> static-typed OOLanguages.
>
>No, it's a particular property of built-in arrays in C++; they are
>simply broken.

Partially agreed, but I think builtin-arrays themselves are not so
problematic. Vlad Harchev's point is "conversion from the derived to the
base" which has ako. semantic conflicit  of subtyping with builtin arrays.
What cause such an undesirable combination of language features? I'd like to
say the HOLE comes from "subtyping" vs. "subclassing" conflict. Note not all
derivation means "subtyping" in C++. The "public" derivation in C++ could
means "subtyping {+ subclassing}". So we should use _very carefully_
"public derivation".


Without abuse of subtyping, the builtin array is not so problematic. That's
much like Scott's suggestion in MEC++.

>> Collison between value and reference :) I haven't seen a clean solution
on
>> this problem yet for conexistence of value and reference.
>
>Here the clean solution is possible in theory (for a new language),
>but would break potentially every C++ program.

More exactly, _value_ meant "value semantics", _reference_ "reference
semantics" in my writing. Could you explain shortly what is the theory?

>> >If 'f' takes two pointers to B and uses them as range of iterators, then
>> >pointer to the current item can never reach the pointer to the end of
range
>> >( or segmentation fault will occur).
>>
>> Subtype polymorphism doesn't exist for such application. Are you sure D
is a
>> subtype of B? What is B? and really D behaves like B?
>
>Well, sizeof (B) != sizeof (D), so no, D doesn't really behave like B
>(otherwise, if you really insisted on that, B and D would have the
>same type ;-)  ).


Physical size has nothing with sutyping relation. We share, I'm sure :)
D shouldn't be a publicly derived class of B, I insist. Real headakes come
from bad relationship, not just bulitin arrays.

>> >Example:
>> >
>> >struct B { int a; };
>> >struct D: public B { char* p; float f; };
>>
>>
>> Why should D be a publicly derived class of B? Just abuse of language
>> feature.
>
>This problem has nothing to do with good/bad uses of OOP.


No. Derivation (Inheritance) is the main feature of OOP in C++. And the
above practive is a typical bad use of derivation - especially interface
inheritance - subtyping.

>> >Frankly speaking, I don't think this is a problem - but I think this is
>> >ideologic inconsistency.
>
>It's history.


Yes, builtin array is a stuff inherited from C. C is not OOL. C-style array
isn't designed for subtype polymorphism.

>> >I only wanted to note, that C++ type system and
>> >strict type checking rules have inconsistenses.
>
>> Agreed, but more accurately, between static OO type system (not just for
>> C++) and static type checking. AFAIK, OOP has no well-defined typing
>> theory yet. Of course, some recent research on this topic presents some
>> possible solutions, for example, (Matching or F-bounded polymorphism),but
>> most are not subtyping (subsumption).
>
>Hum, I don't know about these type theories, but the problem is
>way simplier: there are two cathegories of pointers in C++:
>
>- a pointer to an element whose type is known in an array
>  (where all elements have this type)

- The facility provided for recurively defined (not polymorphic) data types.
- For pass-by-reference by pass-by-value
- dynamic array.

>- a pointer to one object whose type is unknown (just smaller
>  than its declated type); you can't do arithmetic on it
- for polymorphism, deferred (dynamic) binding. In other worlds, pointer
semantics (Java, SmallTalk) by value semantics.

Jaewoo Kim. Dong-A Univ. Korea
---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html              ]





Author: Christopher Eltschka <celtschk@physik.tu-muenchen.de>
Date: 1998/09/08
Raw View
Vlad Harchev wrote:
>
> C++ treats the function parameters of type 'T*' and 'T[]' to be identical
> for purpose of overload resolution ( also it defines implicit conversions
> from one of such types to another). Also it allows conversion from pointer
> to the derived class to pointer to it's base class. This conversions can
> lead to errors that will be hard to find for some users.

Maybe the C++ rules could be changed slightly, so that T[] now
means "a pointer to *exactly* T", while T* retains it's old meaning.
That is, T[] would be equivalent to T*, except that T[] wouldn't
accept derived types.
This would not break C compatibility (since C doesn't know derived
types, and other semantics is not changed), and assuming that one
uses the [] notation only if one really expects an array of T, only
those C++ programs would be broken which are broken anyway (but less
obvious). And even if someone used T[] where he should have used T*,
the fix would be trivial.
Of course the current standard is already fixed, but what about the
next version? Any thoughts?



[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html              ]






Author: christian.bau@isltd.insignia.com (Christian Bau)
Date: 1998/09/09
Raw View
In article <35F516DE.73561CAB@physik.tu-muenchen.de>, Christopher Eltschka
<celtschk@physik.tu-muenchen.de> wrote:

> Vlad Harchev wrote:
> >
> > C++ treats the function parameters of type 'T*' and 'T[]' to be identical
> > for purpose of overload resolution ( also it defines implicit conversions
> > from one of such types to another). Also it allows conversion from pointer
> > to the derived class to pointer to it's base class. This conversions can
> > lead to errors that will be hard to find for some users.
>
> Maybe the C++ rules could be changed slightly, so that T[] now
> means "a pointer to *exactly* T", while T* retains it's old meaning.
> That is, T[] would be equivalent to T*, except that T[] wouldn't
> accept derived types.
> This would not break C compatibility (since C doesn't know derived
> types, and other semantics is not changed), and assuming that one
> uses the [] notation only if one really expects an array of T, only
> those C++ programs would be broken which are broken anyway (but less
> obvious). And even if someone used T[] where he should have used T*,
> the fix would be trivial.
> Of course the current standard is already fixed, but what about the
> next version? Any thoughts?

I think this is a really good idea. It looks very obvious (obvious !=
defined by the language, something can look obvious but be wrong) to me
that if I have a function

   void f (T x[10]) { ... }

x, x+1, x+2 etc. all point to objects of type T, and since we are
discussing C++, they might all point to objects derived from type T. Of
course it doesnt work at all if the actual argument is an array of objects
derived from T!

But you could do it the other way round:

If you have two arrays

   T x [10];
   Derived_from_T y [10];

and call f (y);

the compiler starts with y (which is an array of 10 elements of type
Derived_from_T) which is automatically converted to a pointer of the first
element (type Derived_from_T *) which is then automatically converted to a
pointer to T (type T*). Maybe this should be disallowed; a value of type
"array of X" should be converted to "pointer to X that cannot be
automatically converted").

So f (y) would be illegal; f (&y [0]) would be legal, assuming you wanted
what you get!


[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html              ]






Author: "Jaewoo Kim" <kizoo@esther.donga.ac.kr>
Date: 1998/09/06
Raw View

Vlad Harchev       (      ) <35f062f6.0@monster.ssau.ru>
                              ...
>
>C++ treats the function parameters of type 'T*' and 'T[]' to be identical
>for purpose of overload resolution ( also it defines implicit conversions
>from one of such types to another).
Agreed.

> Also it allows conversion from pointer
> to the derived class to pointer to it's base class. This conversions can
> lead to errors that will be hard to find for some users.

The resulting difficulty is not just for C++, but for nearly all
static-typed OOLanguages.
The core semantics of OOP depends on "subtype polymorphism", which depends
on reference semantics. Without subtyping (subsumption) in C++, how could
you describe the OO semantics of C++? Subtype polymorphism is no more than a
semantic extension of assignment:
    lexp = rexp;

> Let D will be class derived from B. Then, if we have the function 'f' that
>takes parameter 'arr' of type 'array of B', and we have the array 'Darr' of
>D, then 'f' is applicable to 'Darr'. If the function 'f' uses  'arr'  as
>array ( like iteration on it) and sizeof(D) > sizeof(B), then 'f' will
>iterate on pieces of D's - this can have unpredictable results.


Collison between value and reference :) I haven't seen a clean solution on
this problem yet for conexistence of value and reference.

>If 'f' takes two pointers to B and uses them as range of iterators, then
>pointer to the current item can never reach the pointer to the end of range
>( or segmentation fault will occur).


Subtype polymorphism doesn't exist for such application. Are you sure D is a
subtype of B? What is B? and really D behaves like B?

>Example:
>
>struct B { int a; };
>struct D: public B { char* p; float f; };


Why should D be a publicly derived class of B? Just abuse of language
feature.

>D Darr[10];
>void f(B arr[], int n)
>{
>  arr[3].a=2;  /* will corrupt something */
>};


Again, you are trying to take advantage of subtype polymorphism from invalid subtype relationship. Just abuse, I thi
nk.


>Frankly speaking, I don't think this is a problem - but I think this
>is ideologic inconsistency. I only wanted to note, that C++ type
>system and strict type checking rules have inconsistenses.
Agreed, but more accurately, between static OO type system (not just for
C++) and static type checking. AFAIK, OOP has no well-defined typing theory
yet. Of course, some recent research on this topic presents some possible
solutions, for example, (Matching or F-bounded polymorphism), but most are
not subtyping (subsumption).

>This doesn't make C++ less attractive anyway.
Maybe.

Jae Woo Kim, Dong-A Univ. South Korea.



[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html              ]






Author: Valentin Bonnard <bonnardv@pratique.fr>
Date: 1998/09/07
Raw View
Jaewoo Kim <kizoo@esther.donga.ac.kr> writes:

> Vlad Harchev() <35f062f6.0@monster.ssau.ru>

> > Also it allows conversion from pointer
> > to the derived class to pointer to it's base class. This conversions can
> > lead to errors that will be hard to find for some users.
>
> The resulting difficulty is not just for C++, but for nearly all
> static-typed OOLanguages.

No, it's a particular property of built-in arrays in C++; they are
simply broken.

> Collison between value and reference :) I haven't seen a clean solution on
> this problem yet for conexistence of value and reference.

Here the clean solution is possible in theory (for a new language),
but would break potentially every C++ program.

> >If 'f' takes two pointers to B and uses them as range of iterators, then
> >pointer to the current item can never reach the pointer to the end of range
> >( or segmentation fault will occur).
>
> Subtype polymorphism doesn't exist for such application. Are you sure D is a
> subtype of B? What is B? and really D behaves like B?

Well, sizeof (B) != sizeof (D), so no, D doesn't really behave like B
(otherwise, if you really insisted on that, B and D would have the
same type ;-)  ).

> >Example:
> >
> >struct B { int a; };
> >struct D: public B { char* p; float f; };
>
>
> Why should D be a publicly derived class of B? Just abuse of language
> feature.

This problem has nothing to do with good/bad uses of OOP.

> >Frankly speaking, I don't think this is a problem - but I think this is
> >ideologic inconsistency.

It's history.

> >I only wanted to note, that C++ type system and
> >strict type checking rules have inconsistenses.

> Agreed, but more accurately, between static OO type system (not just for
> C++) and static type checking. AFAIK, OOP has no well-defined typing
> theory yet. Of course, some recent research on this topic presents some
> possible solutions, for example, (Matching or F-bounded polymorphism), but
> most are not subtyping (subsumption).

Hum, I don't know about these type theories, but the problem is
way simplier: there are two cathegories of pointers in C++:

- a pointer to an element whose type is known in an array
  (where all elements have this type)

- a pointer to one object whose type is unknown (just smaller
  than its declated type); you can't do arithmetic on it

Example:

Der da[3];
Der* pd = da; // first cathegory
pd += 2; // first cathegory (in order to do +=)
Base* pb = pd; // second cathegory now

These two cathegory support different operations, so they
should have different types. But the language only provide
one type, and built-in arrays are broken anyway, so stay
away from built-in arrays and use vector, with an implementation
where vector<T>::iterator isn't T* but a class type.

--

Valentin Bonnard                mailto:bonnardv@pratique.fr
info about C++/a propos du C++: http://pages.pratique.fr/~bonnardv/
---
[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html              ]





Author: Francis Glassborow <francis@robinton.demon.co.uk>
Date: 1998/09/08
Raw View
In article <35F401C7.424A@pratique.fr>, Valentin Bonnard
<bonnardv@pratique.fr> writes
>These two cathegory support different operations, so they
>should have different types. But the language only provide
>one type, and built-in arrays are broken anyway, so stay
>away from built-in arrays and use vector, with an implementation
>where vector<T>::iterator isn't T* but a class type.

If I understand your argument vector is also broken :)  You cannot have
a vector of polymorphic types, elements of a vector must all be EXACTLY
the same type anything else gives you slicing etc.  However good
implementers wrap their polymorphic types in envelopes.  The iterator
type is a complete side issue because the algorithms work through copy
constructors.  That requires that all elements are the same size.

--
Francis Glassborow


[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html              ]






Author: "Vlad Harchev" <vladhar@imimail.ssau.ru>
Date: 1998/09/04
Raw View
C++ treats the function parameters of type 'T*' and 'T[]' to be identical
for purpose of overload resolution ( also it defines implicit conversions
from one of such types to another). Also it allows conversion from pointer
to the derived class to pointer to it's base class. This conversions can
lead to errors that will be hard to find for some users.
 Let D will be class derived from B. Then, if we have the function 'f' that
takes parameter 'arr' of type 'array of B', and we have the array 'Darr' of
D, then 'f' is applicable to 'Darr'. If the function 'f' uses  'arr'  as
array ( like iteration on it) and sizeof(D) > sizeof(B), then 'f' will
iterate on pieces of D's - this can have unpredictable results.

If 'f' takes two pointers to B and uses them as range of iterators, then
pointer to the current item can never reach the pointer to the end of range
( or segmentation fault will occur).

Example:

struct B { int a; };
struct D: public B { char* p; float f; };

D Darr[10];
void f(B arr[], int n)
{
  arr[3].a=2;  /* will corrupt something */
};

int main() { f(Darr,3); return 0; };

Frankly speaking, I don't think this is a problem - but I think this
is ideologic inconsistency. I only wanted to note, that C++ type
system and strict type checking rules have inconsistenses.
This doesn't make C++ less attractive anyway.



[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html              ]






Author: sbnaran@fermi.ceg.uiuc.edu (Siemel Naran)
Date: 1998/09/04
Raw View
On 4 Sep 1998 16:24:33 GMT, Vlad Harchev <vladhar@imimail.ssau.ru> wrote:

>C++ treats the function parameters of type 'T*' and 'T[]' to be identical
>for purpose of overload resolution ( also it defines implicit conversions
>from one of such types to another). Also it allows conversion from pointer
>to the derived class to pointer to it's base class. This conversions can
>lead to errors that will be hard to find for some users.

Excellent point.  This is array decay.  It sucks, for the most part.

But it does ease notation for dealing with builin arrays.

const int N=10;
int a[N];
int b[N];
std::copy(a,a+N,b);
//std::copy(&a[0],&a[N],&b[0]); // if no array decay


> Let D will be class derived from B. Then, if we have the function 'f' that
>takes parameter 'arr' of type 'array of B', and we have the array 'Darr' of
>D, then 'f' is applicable to 'Darr'. If the function 'f' uses  'arr'  as
>array ( like iteration on it) and sizeof(D) > sizeof(B), then 'f' will
>iterate on pieces of D's - this can have unpredictable results.

Right.  This is "never treat arrays polymorphically" from Scott
Meyers.  If one uses valarray or simplevector, there's no problem.


>Frankly speaking, I don't think this is a problem - but I think this
>is ideologic inconsistency. I only wanted to note, that C++ type
>system and strict type checking rules have inconsistenses.
>This doesn't make C++ less attractive anyway.

OK.  There are lots of things in C++ for backward compatiblity with
C.


--
----------------------------------
Siemel B. Naran (sbnaran@uiuc.edu)
----------------------------------


[ comp.std.c++ is moderated.  To submit articles, try just posting with ]
[ your news-reader.  If that fails, use mailto:std-c++@ncar.ucar.edu    ]
[              --- Please see the FAQ before posting. ---               ]
[ FAQ: http://reality.sgi.com/austern_mti/std-c++/faq.html              ]