I'm not going to say it should be removed, but I'm just wondering if this is
really needed anymore, or maybe to! should instead make use of it.
opCast provides a means to convert an object/struct of one type to another
through an explicit cast operation. This is good as it allows generic code to
perform conversions through a standard call, and the result is a usable type.
I would like to advocate the use of to!() more often in D code than cast(). It
is much more robust, though has slightly different behavior (throws an
exception on class conversions error).
The main issue I see is that we can now convert classes in two forms. To will
make use of both on opCast function and a to function that is found in the
class. (opCast taking precedence in to!). The behavior for using these are
quite different, and be a reason to keep them distinct. In which case this is
just an informative message about their behavior and I'll add it to a wiki.
The example below shows 3 things:
* order of precedence is: opCast, cast, to
* defining opCast can disable casting to any type (its existence prevents
normal casting operations from happening)
* the declared to!() function is not used when an opCast exists but doesn't
match.
Maybe the last one should be fixed.
Here is the code:
import std.conv;
void main() {
B b = new B;
b.i = 5;
A ab = b;
B bcast = cast(B) ab;
assert(b.i == bcast.i); // Fail: used opCast function
B bto = to!B(ab);
assert(b.i == bto.i); // Fail: used opCast function
C c = new C;
c.i = 5;
A ac = c;
//C ccast = cast(C) ac; // Doesn't compile: uses opCast
//C cto = to!C(ac); // Doesn't compile: uses opCast
//
// test.d(13): Error: template instance opCast!(C)
// does not match template declaration opCast(T) if (is(T == B))
//
//assert(c.i == ccast.i);
//assert(c.i == cto.i);
E e = new E;
e.i = 5;
D de = e;
E ecast = cast(E) de;
assert(e.i == ecast.i); // Pass: uses cast
E eto = to!E(de);
assert(e.i == eto.i); // Pass: uses cast
}
class A {
B opCast(T)() if(is(T == B)) {
return new B;
}
C to(T)() if(is(T == C)) {
auto b = new B;
b.i = 5;
return b;
}
}
class B : A {
int i;
}
class C : A {
int i;
}
class D {
E to(T)() if(is(T == E)) {
return new E;
}
}
class E : D {
int i;
}