Is opCast need, we have to!

Jesse Phillips jessekphillips+D at gmail.com
Wed Dec 1 12:56:54 PST 2010


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



More information about the Digitalmars-d mailing list