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;
}

Reply via email to