Implicit type conversion

Michal Minich michal.minich at gmail.com
Mon Jan 10 02:47:49 PST 2011


V Sun, 09 Jan 2011 21:29:32 -0800, Jonathan M Davis wrote:

> 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

Your suggestion to create function overload and bearophile’s bug report 
http://d.puremagic.com/issues/show_bug.cgi?id=5368 to remove variadic 
functions for class objects has given me an idea:

Currently this functionality works only with non-teplated class 
constructors. 

If it were extended to support template and strut constructors, then it 
would make possible to construct objects/struct from function arguments, 
and the interaction with overloading should be more clear because of 
required variadic annotation on function parameter.

In example:

struct S {
    this (T…) (T val) {……}
}

void foo (S s…) { } //<- the dots here expand the constructor parameters

vod main () {
    foo (3); // is the same as:
    foo (S(3));
}

But this is patchy solution. Proper way would be to make new operator 
function opArgConstruct, which would serve as constructor when struct is 
in place of function parameter. This way struct author can control 
availability of this idom. This function should normally just forward the 
call to constructor.

This functionality is need usually for atomic (one valued) type wrappers 
like Variant, RefCounted, Rebindable... If this kind of struct 
constructor is constrained only to accept one argument, it would make 
overloading matter less, and ‘this’ can be used for construction.


More information about the Digitalmars-d-learn mailing list