www.digitalmars.com         C & C++   DMDScript  

digitalmars.D - Defining a single opCast disables explicit cast to base interfaces

reply =?UTF-8?B?QWxpIMOHZWhyZWxp?= <acehreli yahoo.com> writes:
The following program compiles fine:

interface I
{}

class B : I
{}

class C : B
{
     int i;
}

void main()
{
     auto c = new C;

     auto i = cast(I)c;    // compiles
     auto b = cast(B)c;    // compiles
}

Let's add an unrelated opCast to C:

class C : B
{
     int i;

     int opCast(T : int)()
     {
         return i;
     }
}

Now the last two lines of main fail to compile:

Error: template instance opCast!(I) does not match template declaration 
opCast(T : int)()
Error: template instance opCast!(B) does not match template declaration 
opCast(T : int)()

Is this per spec? (Actually, where is the spec? (Trick question. ;) )

There is a workaround: Add a catch-all opCast that forwards to the 
all-powerful std.conv.to:

     T opCast(T)()
     {
         import std.conv;
         return this.to!T;
     }

Now it compiles and works as expected.

However, the question remains...

Thank you,
Ali
Mar 16 2015
next sibling parent =?UTF-8?B?QWxpIMOHZWhyZWxp?= <acehreli yahoo.com> writes:
I forgot to mention that this discussion is carried over from the 
D.learn newsgroup:

   http://forum.dlang.org/thread/uwuvqurfqbetypdlwkdy forum.dlang.org

Ali
Mar 16 2015
prev sibling next sibling parent "jkpl" <jkpl nowhere.fr> writes:
On Tuesday, 17 March 2015 at 05:27:38 UTC, Ali Çehreli wrote:
 The following program compiles fine:

 interface I
 {}

 class B : I
 {}

 class C : B
 {
     int i;
 }

 void main()
 {
     auto c = new C;

     auto i = cast(I)c;    // compiles
     auto b = cast(B)c;    // compiles
 }

 Let's add an unrelated opCast to C:

 class C : B
 {
     int i;

     int opCast(T : int)()
     {
         return i;
     }
 }

 Now the last two lines of main fail to compile:

 Error: template instance opCast!(I) does not match template 
 declaration opCast(T : int)()
 Error: template instance opCast!(B) does not match template 
 declaration opCast(T : int)()

 Is this per spec? (Actually, where is the spec? (Trick 
 question. ;) )

 There is a workaround: Add a catch-all opCast that forwards to 
 the all-powerful std.conv.to:

     T opCast(T)()
     {
         import std.conv;
         return this.to!T;
     }

 Now it compiles and works as expected.

 However, the question remains...

 Thank you,
 Ali
There is also another trick: generally when something cannot be cast then it's often possible to cast it as a pointer to the cast type that is directly derefered. And it work... --- T opCast(T)() { static if(is(T==int)) return i; else return *cast(T*) &this; } --- ...ed until version 2.067 (now it's deprecated because of &this since this is already a ptr).
Mar 17 2015
prev sibling parent Jonathan M Davis via Digitalmars-d <digitalmars-d puremagic.com> writes:
On Monday, March 16, 2015 22:27:36 Ali «ehreli via Digitalmars-d wrote:
 The following program compiles fine:

 interface I
 {}

 class B : I
 {}

 class C : B
 {
      int i;
 }

 void main()
 {
      auto c = new C;

      auto i = cast(I)c;    // compiles
      auto b = cast(B)c;    // compiles
 }

 Let's add an unrelated opCast to C:

 class C : B
 {
      int i;

      int opCast(T : int)()
      {
          return i;
      }
 }

 Now the last two lines of main fail to compile:

 Error: template instance opCast!(I) does not match template declaration
 opCast(T : int)()
 Error: template instance opCast!(B) does not match template declaration
 opCast(T : int)()

 Is this per spec? (Actually, where is the spec? (Trick question. ;) )

 There is a workaround: Add a catch-all opCast that forwards to the
 all-powerful std.conv.to:

      T opCast(T)()
      {
          import std.conv;
          return this.to!T;
      }

 Now it compiles and works as expected.

 However, the question remains...
Defining opCast destroys basically all built-in casts, which I think is a horrible idea. The problem that you're describing was reported a couple of years ago: https://issues.dlang.org/show_bug.cgi?id=9249 But it also affects stuff like shared, and a bug report for that was created four years ago: https://issues.dlang.org/show_bug.cgi?id=5747 And there may be other bug reports for similar issues, but basically, as it stands, declaring opCast borks the built-in casts, forcing you to redefine them all, which is horrible IMHO. But Kenji expressed concern about fixing it in #5747, and no one has stepped up to sort it out. - Jonathan M Davis
Mar 18 2015