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 http://is.gd/ksVli ). 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