D - Bug or feature?
- Helmut Leitner (62/62) Aug 31 2003 In a situation
- Jeroen van Bemmel (13/75) Aug 31 2003 When you declare an array of class A[N], the compiler will allocate
- Vathix (5/100) Aug 31 2003 But D uses class references, which isn't the actual memory but a disguis...
- Riccardo De Agostini (4/5) Sep 01 2003 Polymorphism, maybe?
- Helmut Leitner (17/28) Sep 01 2003 I don't think so.
- Jeroen van Bemmel (3/19) Sep 01 2003 Try adding a datamember to B and see if the casting still works.
- Walter (3/3) Sep 01 2003 It's a bug. Since A[] is an array of references to A, B[] should be
- Jeroen van Bemmel (6/9) Sep 01 2003 Walter,
- Helmut Leitner (9/16) Sep 02 2003 In addition there ar some new pages on Wiki4D
- Walter (6/17) Sep 02 2003 I think that's a good idea. I'll do it when I fix that bug. I remember w...
- DeadCow (16/19) Sep 02 2003 And what about it :
- Walter (7/25) Sep 02 2003 important
- Walter (8/8) Sep 02 2003 I just realized there's another problem:
- Jeroen van Bemmel (44/52) Sep 02 2003 a
- Matthew Wilson (4/12) Sep 09 2003 Large indeed! We need to think of some nice way to prevent this in gener...
- Patrick Down (3/17) Sep 09 2003 Store the class info as part of the array?
- DeadCow (16/19) Sep 09 2003 a
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 arraysIf 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 ?Try adding a datamember to B and see if the casting still works.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 arraysIf 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
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...importantIt'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 anone. -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. -WalterAnd 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...importantIt'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 anIn 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?one. -WalterAnd 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... }
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 bearather 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 bearather 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...Store the class info as part of the array? assert(as.classinfo = A.classinfo);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 bearather 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
"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 bearather 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