Function templates do implicit conversions for their arguments

TommiT tommitissari at hotmail.com
Thu Jul 4 12:00:49 PDT 2013


On Thursday, 4 July 2013 at 18:07:00 UTC, Maxim Fomin wrote:
> On Thursday, 4 July 2013 at 15:59:21 UTC, TommiT wrote:
>> On Thursday, 4 July 2013 at 15:03:54 UTC, Maxim Fomin wrote:
>>> [..]
>>> 2) In case of one parameter, a variable isn't tied to any 
>>> type and usual implicit conversions are applied.
>>
>> Do you mean that if D had the C++ style implicit conversion 
>> operator (using let's say the keyword '@implicit'), then the 
>> following would compile?
>>
>> struct Wrap(T)
>> {
>>    T t;
>> }
>>
>> struct Toy
>> {
>>    alias Wrapped = Wrap!Toy;
>>
>>    @implicit Wrapped opCast(T : Wrapped)()
>>    {
>>        return Wrapped.init;
>>    }
>> }
>>
>> void foo(T)(Wrap!T) { }
>>
>> void main()
>> {
>>    foo(Toy.init);
>> }
>>
>
> Your implicit syntax is redundant. What C++ does is irrelevant. 
> D has alias this.

My implicit cast operator syntax is not redundant because it's 
not the same thing as your alias this example. My example would 
not and should not ever compile.

The difference between alias this relationship and a mere 
implicit conversion operator is that alias this creates an is-a 
relationship, whereas implicit conversion operator does not.


On Thursday, 4 July 2013 at 18:07:00 UTC, Maxim Fomin wrote:
> import std.stdio;
>
> struct Wrap(T)
> {
>     T t;
> }
>
> struct Toy
> {
>     alias get this;
>
>     Wrap!Toy get()
>     {
>         return Wrap!Toy.init;
>     }
> }
>
> void foo(T)(Wrap!T t)
> {
>    writeln(T.stringof);
> }
>
> void main()
> {
>     foo(Toy.init);
> }
>
> Note, that T is Toy, so there were no type conversion during 
> template instantiation. There was argument conversion after 
> instantiation, as it happens usually. Back to foo function 
> accepting slice - dmd does the same thing.

DMD doesn't do the same thing for static arrays. Due to alias 
this, your Toy is a Wrap!Toy for all intents and purposes. 
There's no is-a relationship between a static array type and the 
dynamic array type which it implicitly converts to. What happens 
when static array implicitly converts to dynamic array is the 
same type of implicit conversion which happens when long converts 
to double. There's no is-a relationship between long and double.


>> On Thursday, 4 July 2013 at 15:03:54 UTC, Maxim Fomin wrote:
>>> On Thursday, 4 July 2013 at 13:55:17 UTC, TommiT wrote:
>>>> On Thursday, 4 July 2013 at 13:45:07 UTC, Maxim Fomin wrote:
>>>>> Actually if you pass integer static array, dmd deduces T to 
>>>>> be int, [..]
>>>>
>>>> And that right there, "dmd deduces T to be int", is the crux 
>>>> of the matter. How on earth is DMD able to deduce T to be 
>>>> int, without using the implicit conversion from int[10] to 
>>>> int[] ?
>>>
>>> DMD is stupid, but not that. If it has T[] parameter, and 
>>> int[10] static array which is convertible to int[] is passed, 
>>> T is deduced to be int. What other types T can be? A float, 
>>> object, or pointer to union?
>>
>> So you admit that DMD does implicit conversion during type 
>> deduction?
>
> See above. What type implicit converision did dmd in case of 
> int[10] and int[]. Conversion from int to int?

Here's what the compiler does during type deduction when it sees 
the following function template and its instantiation:

void foo(T)(T[] da) { }

int[10] sa;
foo(sa);

Step 1:
The compiler tries to figure out the type T such as the parameter 
da would have the same type as the argument sa which was passed 
to the function. The complier comes to the conclusion that there 
is not type which would make the type of da the same as the type 
of sa. For example, if T were int, then the type of da would be 
int[] which is not the same as the type of sa which is int[10].

Step 2:
The compiler tries to see if the type of sa could be implicitly 
converted to something. The compiler realises that sa could be 
converted to an instance of type int[]. Then the compiler checks 
if this implicitly converted type could be passed to foo. The 
compiler figures out that if T is int, then the implicitly 
converted type int[] matches exactly with the type of the 
parameter da. Thus, the compiler declares that T must be int.

Step 3:
If the compiler hasn't managed to figure out what T is, it gives 
an error. If it has found out what T is, the compiler declares 
that the type deduction has been successfully accomplished.

To answer your question "What implicit conversion did dmd do in 
the case of int[10] and int[]", see Step 2. At Step 2 the 
compiler does, or rather checks that it's possible to do, the 
implicit conversion from int[10] to int[]. That Step 2 right 
there is what no-one coming from C++ would expect to happen, and 
according to that quote from TDPL, that Step 2 should not happen 
in D.


More information about the Digitalmars-d mailing list