digitalmars.D.learn - Possible Bug with Interfaces in Variadic Functions?
- Daniel Giddings (70/70) Sep 17 2006 Hi All, I'm new to D, and have come across the following problem. I
- Bruno Medeiros (24/112) Sep 26 2006 You are using typeid() comparison incorrectly (no fault of yours, the
- Daniel Giddings (4/28) Sep 26 2006 That works nicely.
Hi All, I'm new to D, and have come across the following problem. I thought it best to ask about it before reporting it as a bug. The problem I've come across is passing a class with an interface base into a variadic function and accessing it as the interface. It crashes the program with some strange behaviour. As far as I can tell I'm not doing anything wrong. Anyway, here's the program: -------------------------------------------------------- import std.stdio; import std.stdarg; class B { char[] f() { return "B.f"; } } class DB : B { char[] f() { return "DB.f"; } } interface I { char[] f(); } class CI : I { char[] f() { return "CI.f"; } } void output( ... ) { for( int i = 0; i < _arguments.length; ++i ) { if( _arguments[i] == typeid(int) ) writefln( "int: %s", va_arg!(int)(_argptr) ); if( _arguments[i] == typeid(char[]) ) writefln( "char[]: %s", va_arg!(char[])(_argptr) ); if( _arguments[i] == typeid(B) ) writefln( "B: %s", va_arg!(B)(_argptr).f() ); if( _arguments[i] == typeid(I) ) { writefln( "Print here for test purposes only - CI appears after this" ); writefln( "I: %s", va_arg!(I)(_argptr).f() ); } } } void main() { output( 5, "Hello World!", new DB, new CI ); } -------------------------------------------------------- The output I'm receiving is: int: 5 char[]: Hello World! B: DB.f Print here for test purposes only - CI appears after this CI I: Error: Access Violation where as I would have expected: int: 5 char[]: Hello World! B: DB.f Print here for test purposes only - CI appears after this I: CI.f I added the class example with a base class as well, and it behaves as I expected. Is there anything I'm doing incorrectly? It's easy enough to get around the problem for what I want to do, but I thought I'd bring it up. Cheers, :-) Dan
Sep 17 2006
Daniel Giddings wrote:Hi All, I'm new to D, and have come across the following problem. I thought it best to ask about it before reporting it as a bug. The problem I've come across is passing a class with an interface base into a variadic function and accessing it as the interface. It crashes the program with some strange behaviour. As far as I can tell I'm not doing anything wrong. Anyway, here's the program: -------------------------------------------------------- import std.stdio; import std.stdarg; class B { char[] f() { return "B.f"; } } class DB : B { char[] f() { return "DB.f"; } } interface I { char[] f(); } class CI : I { char[] f() { return "CI.f"; } } void output( ... ) { for( int i = 0; i < _arguments.length; ++i ) { if( _arguments[i] == typeid(int) ) writefln( "int: %s", va_arg!(int)(_argptr) ); if( _arguments[i] == typeid(char[]) ) writefln( "char[]: %s", va_arg!(char[])(_argptr) ); if( _arguments[i] == typeid(B) ) writefln( "B: %s", va_arg!(B)(_argptr).f() ); if( _arguments[i] == typeid(I) ) { writefln( "Print here for test purposes only - CI appears after this" ); writefln( "I: %s", va_arg!(I)(_argptr).f() ); } } } void main() { output( 5, "Hello World!", new DB, new CI ); } -------------------------------------------------------- The output I'm receiving is: int: 5 char[]: Hello World! B: DB.f Print here for test purposes only - CI appears after this CI I: Error: Access Violation where as I would have expected: int: 5 char[]: Hello World! B: DB.f Print here for test purposes only - CI appears after this I: CI.f I added the class example with a base class as well, and it behaves as I expected. Is there anything I'm doing incorrectly? It's easy enough to get around the problem for what I want to do, but I thought I'd bring it up. Cheers, :-) DanYou are using typeid() comparison incorrectly (no fault of yours, the spec is erroneous, see http://d.puremagic.com/issues/show_bug.cgi?id=373 ). Using '==' to compare TypeInfos will test the equality of the type's "archetype", that is, if they are both a struct, a pointer, a class, etc. Apparently interfaces and classes belong to the same archetype (which is class), so any TypeInfo equality comparison between any of these will allways result true. Using 'is' to compare TypeInfos will test for an exact type match, which is also not what you, since it will disregard polymorphism. Here's how you can do it: // Check for class archetype: if( _arguments[i] == typeid(Object) ) { auto obj = va_arg!(Object)(_argptr); // check if obj is-a I if( (cast(I) obj) != null ) { I myi = cast(I) obj; // use myi writefln(myi.f()); } } -- Bruno Medeiros - MSc in CS/E student http://www.prowiki.org/wiki4d/wiki.cgi?BrunoMedeiros#D
Sep 26 2006
That works nicely. Thanks, :-) Dan Bruno Medeiros wrote:You are using typeid() comparison incorrectly (no fault of yours, the spec is erroneous, see http://d.puremagic.com/issues/show_bug.cgi?id=373 ). Using '==' to compare TypeInfos will test the equality of the type's "archetype", that is, if they are both a struct, a pointer, a class, etc. Apparently interfaces and classes belong to the same archetype (which is class), so any TypeInfo equality comparison between any of these will allways result true. Using 'is' to compare TypeInfos will test for an exact type match, which is also not what you, since it will disregard polymorphism. Here's how you can do it: // Check for class archetype: if( _arguments[i] == typeid(Object) ) { auto obj = va_arg!(Object)(_argptr); // check if obj is-a I if( (cast(I) obj) != null ) { I myi = cast(I) obj; // use myi writefln(myi.f()); } }
Sep 26 2006