D - Bug or feature?
- Helmut Leitner <helmut.leitner chello.at> Aug 31 2003
- "Jeroen van Bemmel" <someone somewhere.com> Aug 31 2003
- "Vathix" <vathix dprogramming.com> Aug 31 2003
- "Riccardo De Agostini" <riccardo.de.agostini email.it> Sep 01 2003
- Helmut Leitner <helmut.leitner chello.at> Sep 01 2003
- "Jeroen van Bemmel" <someone somewhere.com> Sep 01 2003
- "Walter" <walter digitalmars.com> Sep 01 2003
- "Jeroen van Bemmel" <someone somewhere.com> Sep 01 2003
- Helmut Leitner <leitner hls.via.at> Sep 02 2003
- "Walter" <walter digitalmars.com> Sep 02 2003
- "DeadCow" <deadcow-remove-this free.fr> Sep 02 2003
- "Walter" <walter digitalmars.com> Sep 02 2003
- "Walter" <walter digitalmars.com> Sep 02 2003
- "Jeroen van Bemmel" <someone somewhere.com> Sep 02 2003
- "Matthew Wilson" <matthew stlsoft.org> Sep 09 2003
- Patrick Down <Patrick_member pathlink.com> Sep 09 2003
- "DeadCow" <deadcow-remove-this free.fr> Sep 09 2003
In a situation
class B:A { ... }
I can call
foo(A a);
passing instances of class A or class B.
Now I would like to write a function
foo(A [] atab)
that I can pass arrays of instances of A or B.
But I can't make it happen. It won't compile.
It's the same when I use interfaces.
My sample code (contains both trys):
interface Printable {
void print();
}
class A:Printable {
void print() { printf("A\n"); }
}
class B:A {
void print() { printf("B\n"); }
}
void Print(A a) {
a.print();
}
void ArrayPrint(A a[]) {
for(int i=0; i<a.length; i++) {
printf("[%d]: ",i); a[i].print();
}
}
void PrintablePrint(Printable p) {
printf("via Interface: "); p.print();
}
void ArrayPrintablePrint(Printable [] p) {
for(int i=0; i<p.length; i++) {
printf("via Interface [%d]: ",i); PrintablePrint(p[i]);
}
}
int main ()
{
A atab[];
atab.length=3;
atab[0]= new A;
atab[1]= new A;
atab[2]= new A;
Print(atab[0]);
ArrayPrint(atab);
B btab[];
btab.length=3;
btab[0]= new B;
btab[1]= new B;
btab[2]= new B;
Print(btab[0]);
// ArrayPrint(btab); // doesn't compile
PrintablePrint(atab[0]);
PrintablePrint(btab[0]);
// ArrayPrintablePrint(atab); // doesn't compile
// ArrayPrintablePrint(btab); // doesn't compile
return 0;
}
Shouldn't the 3 commented lines work?
--
Helmut Leitner leitner hls.via.at
Graz, Austria www.hls-software.com
Aug 31 2003
When you declare an array of class A[N], the compiler will allocate N*sizeof(A) + a bit of memory for it. You cannot then store an element B (derived from A) in that same array, since sizeof(B) is typically larger than sizeof(A) which would confuse indexing calculations. So basically, the case here is that A[] is a totally different type than B[], even though B may be derived from A. 'Type substitutionability' (somebody rephrase this :)as a result of inheritance does not apply to arrays You would be able to create an array of _pointers_ to A, which could then point to instances of B as you like. The answer to your question should thus be: feature "Helmut Leitner" <helmut.leitner chello.at> wrote in message news:3F524DD2.84943F44 chello.at...In a situation class B:A { ... } I can call foo(A a); passing instances of class A or class B. Now I would like to write a function foo(A [] atab) that I can pass arrays of instances of A or B. But I can't make it happen. It won't compile. It's the same when I use interfaces. My sample code (contains both trys): interface Printable { void print(); } class A:Printable { void print() { printf("A\n"); } } class B:A { void print() { printf("B\n"); } } void Print(A a) { a.print(); } void ArrayPrint(A a[]) { for(int i=0; i<a.length; i++) { printf("[%d]: ",i); a[i].print(); } } void PrintablePrint(Printable p) { printf("via Interface: "); p.print(); } void ArrayPrintablePrint(Printable [] p) { for(int i=0; i<p.length; i++) { printf("via Interface [%d]: ",i); PrintablePrint(p[i]); } } int main () { A atab[]; atab.length=3; atab[0]= new A; atab[1]= new A; atab[2]= new A; Print(atab[0]); ArrayPrint(atab); B btab[]; btab.length=3; btab[0]= new B; btab[1]= new B; btab[2]= new B; Print(btab[0]); // ArrayPrint(btab); // doesn't compile PrintablePrint(atab[0]); PrintablePrint(btab[0]); // ArrayPrintablePrint(atab); // doesn't compile // ArrayPrintablePrint(btab); // doesn't compile return 0; } Shouldn't the 3 commented lines work? -- Helmut Leitner leitner hls.via.at Graz, Austria www.hls-software.com
Aug 31 2003
But D uses class references, which isn't the actual memory but a disguised pointer (?) so I think it should work. It would be a problem for structs, but they aren't allowed to have inheritance. "Jeroen van Bemmel" <someone somewhere.com> wrote in message news:bitnrj$204b$1 digitaldaemon.com...When you declare an array of class A[N], the compiler will allocate N*sizeof(A) + a bit of memory for it. You cannot then store an element B (derived from A) in that same array, since sizeof(B) is typically larger than sizeof(A) which would confuse indexing calculations. So basically, the case here is that A[] is a totally different type than B[], even though B may be derived from A. 'Type substitutionability' (somebody rephrase this :)as a result of inheritance does not apply to arrays You would be able to create an array of _pointers_ to A, which could then point to instances of B as you like. The answer to your question should thus be: feature "Helmut Leitner" <helmut.leitner chello.at> wrote in message news:3F524DD2.84943F44 chello.at...In a situation class B:A { ... } I can call foo(A a); passing instances of class A or class B. Now I would like to write a function foo(A [] atab) that I can pass arrays of instances of A or B. But I can't make it happen. It won't compile. It's the same when I use interfaces. My sample code (contains both trys): interface Printable { void print(); } class A:Printable { void print() { printf("A\n"); } } class B:A { void print() { printf("B\n"); } } void Print(A a) { a.print(); } void ArrayPrint(A a[]) { for(int i=0; i<a.length; i++) { printf("[%d]: ",i); a[i].print(); } } void PrintablePrint(Printable p) { printf("via Interface: "); p.print(); } void ArrayPrintablePrint(Printable [] p) { for(int i=0; i<p.length; i++) { printf("via Interface [%d]: ",i); PrintablePrint(p[i]); } } int main () { A atab[]; atab.length=3; atab[0]= new A; atab[1]= new A; atab[2]= new A; Print(atab[0]); ArrayPrint(atab); B btab[]; btab.length=3; btab[0]= new B; btab[1]= new B; btab[2]= new B; Print(btab[0]); // ArrayPrint(btab); // doesn't compile PrintablePrint(atab[0]); PrintablePrint(btab[0]); // ArrayPrintablePrint(atab); // doesn't compile // ArrayPrintablePrint(btab); // doesn't compile return 0; } Shouldn't the 3 commented lines work? -- Helmut Leitner leitner hls.via.at Graz, Austria www.hls-software.com
Aug 31 2003
"Jeroen van Bemmel" <someone somewhere.com> ha scritto nel messaggio news:bitnrj$204b$1 digitaldaemon.com...[...] 'Type substitutionability' (somebody rephrase this :) [...]
Polymorphism, maybe? Ric
Sep 01 2003
Jeroen van Bemmel wrote:When you declare an array of class A[N], the compiler will allocate N*sizeof(A) + a bit of memory for it.
I don't think so. I think there is an array reference consisting of - array size - pointer to start of array and the array of object reference - N * 4 byte of heap storage and perhaps (if initialized) - N * sizeof(A) of heap storage for the instances But I'm can't be quite sure about these implementation detail.You cannot then store an element B (derived from A) in that same array, since sizeof(B) is typically larger than sizeof(A) which would confuse indexing calculations. So basically, the case here is that A[] is a totally different type than B[], even though B may be derived from A. 'Type substitutionability' (somebody rephrase this :)as a result of inheritance does not apply to arrays
If I cast: ArrayPrint( cast(A []) btab ); it compiles and works, but this type of casting seems very unsafe to me (if I cast to the interface Printable it also compiles but <crashes>). -- Helmut Leitner leitner hls.via.at Graz, Austria www.hls-software.com
Sep 01 2003
But I'm can't be quite sure about these implementation detail.
I'm not sure either, my posting was based on C++ semantics. Did you try the pointer-to-A array ?You cannot then store an element B (derived from A) in that same array, since sizeof(B) is typically larger than sizeof(A) which would confuse indexing calculations. So basically, the case here is that A[] is a totally different type than B[], even though B may be derived from A. 'Type substitutionability' (somebody rephrase this :)as a result of inheritance does not apply to arrays
If I cast: ArrayPrint( cast(A []) btab ); it compiles and works, but this type of casting seems very unsafe to me (if I cast to the interface Printable it also compiles but <crashes>).
Try adding a datamember to B and see if the casting still works.-- Helmut Leitner leitner hls.via.at Graz, Austria www.hls-software.com
Sep 01 2003
It's a bug. Since A[] is an array of references to A, B[] should be implicitly convertible to A[]. Thanks for finding it, this is an important one. -Walter
Sep 01 2003
Walter, Could you add this information to the 'Arrays' section of the D webpages? It's counter intuitive (at least for C++ people like me) and it makes me give wrong answers :) "Walter" <walter digitalmars.com> wrote in message news:bj0e06$2nf0$1 digitaldaemon.com...It's a bug. Since A[] is an array of references to A, B[] should be implicitly convertible to A[]. Thanks for finding it, this is an important one. -Walter
Sep 01 2003
Jeroen van Bemmel wrote:Walter, Could you add this information to the 'Arrays' section of the D webpages? It's counter intuitive (at least for C++ people like me) and it makes me give wrong answers :)
In addition there ar some new pages on Wiki4D <http://www.prowiki.org/wiki4d/wiki.cgi?NotesForProgrammersUsedTo> <http://www.prowiki.org/wiki4d/wiki.cgi?NotesForProgrammersUsedTo/CplusPlus> so that we can gather hints or special considerations for the users of various languages. -- Helmut Leitner leitner hls.via.at Graz, Austria www.hls-software.com
Sep 02 2003
I think that's a good idea. I'll do it when I fix that bug. I remember when I first was trying to learn Java I came to grief several times from forgetting that Java does objects by reference. "Jeroen van Bemmel" <someone somewhere.com> wrote in message news:bj1adh$tkl$1 digitaldaemon.com...Walter, Could you add this information to the 'Arrays' section of the D webpages? It's counter intuitive (at least for C++ people like me) and it makes me give wrong answers :) "Walter" <walter digitalmars.com> wrote in message news:bj0e06$2nf0$1 digitaldaemon.com...It's a bug. Since A[] is an array of references to A, B[] should be implicitly convertible to A[]. Thanks for finding it, this is an
one. -Walter
Sep 02 2003
"Walter" <walter digitalmars.com> a écrit dans le message news: bj0e06$2nf0$1 digitaldaemon.com...It's a bug. Since A[] is an array of references to A, B[] should be implicitly convertible to A[]. Thanks for finding it, this is an important one. -Walter
And what about it : class A {} class B : A { void crash() {}; } void doSomethingWrong( A[] as ) { as ~= new A(); // doh ! } void main() { B[] bs; doSomethingWrong(bs); // implicitly convertible you said bs[0].crash(); // oops... } -- Nicolas Repiquet
Sep 02 2003
"DeadCow" <deadcow-remove-this free.fr> wrote in message news:bj1vu2$1tke$1 digitaldaemon.com..."Walter" <walter digitalmars.com> a écrit dans le message news: bj0e06$2nf0$1 digitaldaemon.com...It's a bug. Since A[] is an array of references to A, B[] should be implicitly convertible to A[]. Thanks for finding it, this is an
one. -Walter
And what about it : class A {} class B : A { void crash() {}; } void doSomethingWrong( A[] as ) { as ~= new A(); // doh ! } void main() { B[] bs; doSomethingWrong(bs); // implicitly convertible you said bs[0].crash(); // oops... }
In this case, 'as' is an in variable, and resizing it won't affect bs. If it was rewritten so that 'as' is inout, then it will crash as you showed. I don't know what to do about this case - perhaps disallow such implicit conversions for an inout or out parameter?
Sep 02 2003
I just realized there's another problem:
void doSomethingWrong(A[] as)
{
as[0] = new A();
}
Now, main() will think that as[0] is a B, and crash away. This seems to be a
rather large hole in typesafety. The same problem exists in C++, so maybe
nobody cares anyway <g>.
Sep 02 2003
"Walter" <walter digitalmars.com> wrote in message news:bj2qee$1od$1 digitaldaemon.com...I just realized there's another problem: void doSomethingWrong(A[] as) { as[0] = new A(); } Now, main() will think that as[0] is a B, and crash away. This seems to be
rather large hole in typesafety. The same problem exists in C++, so maybe nobody cares anyway <g>.
Interesting test case. Java throws a 'java.lang.ArrayStoreException' here, at the point where you try to store the A in the array that is really B C++ is different, since arrays use store by value unless you make it an array of pointers. If I do, e.g. #include <iostream> using namespace std; class A { public: virtual void print() { cout << 'A' << endl; } }; class B : public A { public: virtual void print() { cout << 'B' << endl; } virtual void B_func() { cout << 'C' << endl; } }; static void test( A* as[] ) { as[0]->print(); as[0] = new A(); } int main( int argc, char* argv[] ) { B** bs = new (B*)[1]; bs[0] = new B(); test( (A**) bs ); // needs explicit cast bs[0]->B_func(); // crashes, probably because the vtable of A's class does not contain a pointer to B_func } So the need for an explicit cast should tell you that you're trying to do something illegal: B** is not implicitly translated to A** Although a rare case, I prefer the Java solution. The Java docs mention: Object x[] = new String[3]; x[0] = new Integer(0); as a typical case where such an exception would be thrown, and a more common one for that. Applicable to D too, Walter?
Sep 02 2003
I just realized there's another problem: void doSomethingWrong(A[] as) { as[0] = new A(); } Now, main() will think that as[0] is a B, and crash away. This seems to be
rather large hole in typesafety. The same problem exists in C++, so maybe nobody cares anyway <g>.
Large indeed! We need to think of some nice way to prevent this in general, but to allow the programmer to do it if s/he *really* wants to (kind of like poking COM vtable entries)
Sep 09 2003
In article <bjldla$2j4j$2 digitaldaemon.com>, Matthew Wilson says...I just realized there's another problem: void doSomethingWrong(A[] as) { as[0] = new A(); } Now, main() will think that as[0] is a B, and crash away. This seems to be
rather large hole in typesafety. The same problem exists in C++, so maybe nobody cares anyway <g>.
Large indeed! We need to think of some nice way to prevent this in general, but to allow the programmer to do it if s/he *really* wants to (kind of like poking COM vtable entries)
Store the class info as part of the array? assert(as.classinfo = A.classinfo);
Sep 09 2003
"Walter" <walter digitalmars.com> a écrit dans le message news: bj2qee$1od$1 digitaldaemon.com...Now, main() will think that as[0] is a B, and crash away. This seems to be
rather large hole in typesafety. The same problem exists in C++, so maybe nobody cares anyway <g>.
What about templates ? class A {} class B {} template TFoo(T) { T[] ts; void add(T t) { ts ~= t; } } void doSomethingWrong( TFoo(Object) t ) { t.add(new B()); } instance TFoo(A) a; doSomethingWrong( a ); // implicit conversion -- Nicolas Repiquet
Sep 09 2003









"Vathix" <vathix dprogramming.com> 