Implicit type conversion

Jonathan M Davis jmdavisProg at
Sun Jan 9 21:29:32 PST 2011

On Saturday 08 January 2011 13:16:54 Michal Minich wrote:
> Use case:
> import std.variant;
> void foo (Variant v) {}
> void main () {
>     Variant v = 3; // ok, this (....) called
>     v = 3;         // ok, opAssing  called
>     foo (v);       // ok, struct copy, this(this) called
>     foo (3);       // error
> }
> I'm trying to understand what is needed to make this work from language
> design perspective. Is there already known/proposed solution to make this
> work? What comes to my mind as first - Variant constructor should be
> called on last line, the same way as on the first. But maybe to solve
> this, another operator is needed, opImplicitConvertFrom ...

There are definitely folks who want opImplicitCast (I think that it's pretty much 
going to be necessary to get std.typecons.Rebindable to work entirely 
correctly), and there's at least a decent chance that it will get added, but in 
general, D avoids implicit casting in order to avoid issues where you call 
functions which you don't really want to call (see ). 
Regardless, opImplicitCast wouldn't help you here anyway, because you need to 
cast from an int to a Variant rather than the other way around, and it's not 
like int is going to have opImplicitCast defined, even if it did exist. 
Generally, you just need to give the correct type, which in this case would 
presumably mean foo(Variant(3)). It might be a bid annoying, but it avoids 
problems where you end up calling a function overload that you didn't intend to. 
If you really don't want to do that, then I believe that you're going to have to 
create another function overload for Foo which takes an int and deals with the 
conversion to Variant for you.

> Second question. Why is needed to have both - strut constructor (this)
> and opAssing. In variant case, constructor just forwards to opAssing.
> From high level point of view, I don't see any reason both should behave
> differently...

There could be a difference of efficiency depending on the type. It could be more 
efficient to do something differently in one. For instance, that's why we have both 
opAssign and opOpAssign. Technically, you could just not have opOpAssign and use 
the combination of opAssign and opBinary to do it, but then you're likely to end 
up with extra heap allocations and the like. It could be the same with a 
constructor and opAssign, depending on the type.

For the most part, D has tried to reduce how many operators you have to declare 
when they're related (such us using opCmp() to give you <, <=, >=, and >), but 
it does create extra ones in cases where there's a good chance that it's more 
efficient to have separate definitions (such as using opEquals() for == and != 
rather than using opCmp() for that).

- Jonathan M Davis

More information about the Digitalmars-d-learn mailing list