March 01, 2013
http://d.puremagic.com/issues/show_bug.cgi?id=1528



--- Comment #19 from Kenji Hara <k.hara.pg@gmail.com> 2013-03-01 03:26:51 PST ---
(In reply to comment #17)
> > template type parameter deduction without specialization always be MATCHconvert
> 
> AFAIK this is a kludgy implementation detail to make specialization work. The last time we worked on that we concluded (with Daniel Murphy?) that there should be an additional level between convert and exact. I don't remember the details right now, but I'll try to find the relevant discussion.

Are you saying about MATCHdeduced? I had seen the Daniel Murphy's pull request somewhere, but it is completely unnecessary.

In IFTI, the match level for template arguments and for function arguments are distinguished. The former is prior than the latter, so there is 3 * 3 + 1 match level in IFTI.

  For tiargs: exact or const or convert  (3)
  For funargs: exact or const or convert  (* 3)
  noatch (+ 1)

During implementation, I found that the two matching levels had not be separated correctly (the bug was in TemplateDeclaration::deduceFunctionTemplateMatch). After fixing the bug, I can believe that MATCHdeduced is not need anymore.

-- 
Configure issuemail: http://d.puremagic.com/issues/userprefs.cgi?tab=email
------- You are receiving this mail because: -------
March 01, 2013
http://d.puremagic.com/issues/show_bug.cgi?id=1528



--- Comment #20 from timon.gehr@gmx.ch 2013-03-01 03:40:36 PST ---
(In reply to comment #19)
> (In reply to comment #17)
> ...
> 
> In IFTI, the match level for template arguments and for function arguments are distinguished. The former is prior than the latter, so there is 3 * 3 + 1 match level in IFTI.
> 
>   For tiargs: exact or const or convert  (3)
>   For funargs: exact or const or convert  (* 3)
>   noatch (+ 1)
> ...

It can be seen that way. They are ordered from worst to best like this:

no match
ifti convert
function convert
ifti const
function const
ifti exact
function exact

-- 
Configure issuemail: http://d.puremagic.com/issues/userprefs.cgi?tab=email
------- You are receiving this mail because: -------
March 01, 2013
http://d.puremagic.com/issues/show_bug.cgi?id=1528



--- Comment #21 from Kenji Hara <k.hara.pg@gmail.com> 2013-03-01 03:55:37 PST ---
(In reply to comment #20)
> (In reply to comment #19)
> > (In reply to comment #17)
> > ...
> > 
> > In IFTI, the match level for template arguments and for function arguments are distinguished. The former is prior than the latter, so there is 3 * 3 + 1 match level in IFTI.
> > 
> >   For tiargs: exact or const or convert  (3)
> >   For funargs: exact or const or convert  (* 3)
> >   noatch (+ 1)
> > ...
> 
> It can be seen that way. They are ordered from worst to best like this:

More precisely:

MATCHnomatch
tiargs:MATCHconvert / funarg:MATCHconvert
tiargs:MATCHconvert / funarg:MATCHconst
tiargs:MATCHconvert / funarg:MATCHexact
tiargs:MATCHconst   / funarg:MATCHconvert
tiargs:MATCHconst   / funarg:MATCHconst
tiargs:MATCHconst   / funarg:MATCHexact
tiargs:MATCHexact   / funarg:MATCHconvert
tiargs:MATCHexact   / funarg:MATCHconst
tiargs:MATCHexact   / funarg:MATCHexact

Additionally, when comparing normal function and template function matching, tiargs MATCH level is treated as equal to funargs level.

-- 
Configure issuemail: http://d.puremagic.com/issues/userprefs.cgi?tab=email
------- You are receiving this mail because: -------
March 01, 2013
http://d.puremagic.com/issues/show_bug.cgi?id=1528



--- Comment #22 from timon.gehr@gmx.ch 2013-03-01 11:48:00 PST ---
(In reply to comment #21)
> (In reply to comment #20)
> > (In reply to comment #19)
> > > (In reply to comment #17)
> > > ...
> > > 
> > > In IFTI, the match level for template arguments and for function arguments are distinguished. The former is prior than the latter, so there is 3 * 3 + 1 match level in IFTI.
> > > 
> > >   For tiargs: exact or const or convert  (3)
> > >   For funargs: exact or const or convert  (* 3)
> > >   noatch (+ 1)
> > > ...
> > 
> > It can be seen that way. They are ordered from worst to best like this:
> 
> More precisely:
> 
> MATCHnomatch
> tiargs:MATCHconvert / funarg:MATCHconvert
> tiargs:MATCHconvert / funarg:MATCHconst
> tiargs:MATCHconvert / funarg:MATCHexact
> tiargs:MATCHconst   / funarg:MATCHconvert
> tiargs:MATCHconst   / funarg:MATCHconst
> tiargs:MATCHconst   / funarg:MATCHexact
> tiargs:MATCHexact   / funarg:MATCHconvert
> tiargs:MATCHexact   / funarg:MATCHconst
> tiargs:MATCHexact   / funarg:MATCHexact
> 
> Additionally, when comparing normal function and template function matching, tiargs MATCH level is treated as equal to funargs level.

Ah, now I see what you mean. You are matching foo!tiargs(funargs).

I was talking about resolving template vs. non-template overloads in the
foo(funargs) setting.

-- 
Configure issuemail: http://d.puremagic.com/issues/userprefs.cgi?tab=email
------- You are receiving this mail because: -------
March 02, 2013
http://d.puremagic.com/issues/show_bug.cgi?id=1528



--- Comment #23 from Kenji Hara <k.hara.pg@gmail.com> 2013-03-01 18:17:08 PST ---
(In reply to comment #22)
> Ah, now I see what you mean. You are matching foo!tiargs(funargs).
> 
> I was talking about resolving template vs. non-template overloads in the
> foo(funargs) setting.

I'm talking about both. You can think type parameters deduction and function arguments matching separately. For example:

void foo(T)(T) {}
void foo(T:int)(T) {}

With first overload version,
Phase 1: T is deduced to int. ==> MATCHconvert.
Phase 2: 1 matches T (==already deduced to int). ==> MATCHexact.

With second overload version,
Phase 1: T is deduced to int and is specialized to int. ==> MATCHexact.
Phase 2: 1 matches T (==already deduced to int). ==> MATCHexact.

Finally, foo(T)(T) is less specialized than foo(T:int)(T).

I explain more complicated case.

void bar(int, int) {}
void bar(T)(T, int) {}
bar(1, 1L);

With first overload version,
Phase 1: normal function is treated as having empty template parameter list, so
         matching is always exact ==> MATCHexact
Phase 2: int <- 1 == MATCHexact, int <- 1L == MATCHconvert. ==> MATCHconvert

With second overload version,
Phase 1: T <- typeof(int). ==> MATCHconvert
Phase 2: T <- 1 == MATCHexact, int <- 1L == MATCHconvert ==> MATCHconvert

From the comparison of Phase 1 result, bar(int, int) is more specialized than
bar(T)(T, int) for function arguments (1, 1L).

-- 
Configure issuemail: http://d.puremagic.com/issues/userprefs.cgi?tab=email
------- You are receiving this mail because: -------
March 14, 2013
http://d.puremagic.com/issues/show_bug.cgi?id=1528



--- Comment #24 from Martin Nowak <code@dawg.eu> 2013-03-14 08:46:43 PDT ---
(In reply to comment #23)

I think this rule is problematic for the function vs. deduced parameter case.

// vs deduced parameter
int f3(int a) { return 1; }
int f3(T)(T b) { return 2; }
f3(1L);

With first overload version,
Phase 1: normal function is treated as having empty template parameter list, so
         matching is always exact  ==> MATCHexact
Phase 2: int <- 1L == MATCHconvert ==> MATCHconvert

With second overload version,
Phase 1: T <- typeof(1L) = long    ==> MATCHconvert
Phase 2: T <- 1L == MATCHexact     ==> MATCHexact

- the current implementation in the pull request chooses
  the function whereas comment #13 and #16 suggest to go
  with the function template

https://github.com/9rnsr/dmd/blob/b141e29e29b1ec43873c7e0374d27d3fbbae8085/test/runnable/overload.d#L216 https://github.com/9rnsr/dmd/blob/b141e29e29b1ec43873c7e0374d27d3fbbae8085/test/runnable/overload.d#L279

- C++ chooses the function template

- For me it's counterintuitive to call with conversion when an exact
  match can be instantiated. Even an ambiguous error seems more reasonable to
me.

-- 
Configure issuemail: http://d.puremagic.com/issues/userprefs.cgi?tab=email
------- You are receiving this mail because: -------
March 14, 2013
http://d.puremagic.com/issues/show_bug.cgi?id=1528



--- Comment #25 from Martin Nowak <code@dawg.eu> 2013-03-14 08:52:21 PDT ---
I find the C++ rule pretty plausible.

> In most cases a function template behaves just like a normal function when considering overload resolution. The template argument deduction is applied, if it succeeds, the function is added to the candidates set. Such a function is handled like any other function, except when two viable functions are equally good, the non-template one is selected. In case both are a specialisation of a function template, partial ordering rules are applied. The partial ordering rules are out of the scope of this article.

http://accu.org/index.php/journals/268#d0e340

-- 
Configure issuemail: http://d.puremagic.com/issues/userprefs.cgi?tab=email
------- You are receiving this mail because: -------
March 14, 2013
http://d.puremagic.com/issues/show_bug.cgi?id=1528



--- Comment #26 from Kenji Hara <k.hara.pg@gmail.com> 2013-03-14 09:01:49 PDT ---
(In reply to comment #24)
> (In reply to comment #23)
> 
> I think this rule is problematic for the function vs. deduced parameter case.
> 
> // vs deduced parameter
> int f3(int a) { return 1; }
> int f3(T)(T b) { return 2; }
> f3(1L);
> 
> With first overload version,
> Phase 1: normal function is treated as having empty template parameter list, so
>          matching is always exact  ==> MATCHexact
> Phase 2: int <- 1L == MATCHconvert ==> MATCHconvert
> 
> With second overload version,
> Phase 1: T <- typeof(1L) = long    ==> MATCHconvert
> Phase 2: T <- 1L == MATCHexact     ==> MATCHexact
> 
> - the current implementation in the pull request chooses
>   the function whereas comment #13 and #16 suggest to go
>   with the function template
> 
> https://github.com/9rnsr/dmd/blob/b141e29e29b1ec43873c7e0374d27d3fbbae8085/test/runnable/overload.d#L216 https://github.com/9rnsr/dmd/blob/b141e29e29b1ec43873c7e0374d27d3fbbae8085/test/runnable/overload.d#L279
> 
> - C++ chooses the function template
> 
> - For me it's counterintuitive to call with conversion when an exact
>   match can be instantiated. Even an ambiguous error seems more reasonable to
> me.

Right now I think that was little bad example.

Ques. Why f3(1L) chooses non-template version?

Short Ans. Because the given argument 1L is a literal.

Long Ans.
In D, literals works as like polysemous value. 1L is implicitly convertible to
int by Value Range Propagation, so it matchs with MATCHconvert.

If you give a runtime long value to f3:

long n;
f3(n);

With first overload version,
Phase 1: normal function is treated as having empty template parameter list, so
         matching is always exact  ==> MATCHexact
Phase 2: int <- n == MATCHnomatch    (changed!!)

With second overload version,
Phase 1: T <- typeof(1L) = long    ==> MATCHconvert
Phase 2: T <- 1L == MATCHexact     ==> MATCHexact

So it will choose template version. How about?

-- 
Configure issuemail: http://d.puremagic.com/issues/userprefs.cgi?tab=email
------- You are receiving this mail because: -------
March 14, 2013
http://d.puremagic.com/issues/show_bug.cgi?id=1528



--- Comment #27 from timon.gehr@gmx.ch 2013-03-14 15:34:50 PDT ---
(In reply to comment #25)
> I find the C++ rule pretty plausible.
> 
> > In most cases a function template behaves just like a normal function when considering overload resolution. The template argument deduction is applied, if it succeeds, the function is added to the candidates set. Such a function is handled like any other function, except when two viable functions are equally good, the non-template one is selected. In case both are a specialisation of a function template, partial ordering rules are applied. The partial ordering rules are out of the scope of this article.
> 
> http://accu.org/index.php/journals/268#d0e340

C++ does not have template value parameters. The C++ behaviour is approximated closely when IFTI type parameter deduction is treated as exact match. (There is no reason to do anything else, a type is required, and a type is given.)

However, it is not too clear that there must be one matching level for the template and one for the function.

@Kenji, why do you think this is required? Why does one matching level for everything not suffice?

Eg, I think the following code should not compile and show an ambiguity error.

void foo(double a)(int b){ }
void foo(int a)(double b){ }

void main(){
    foo!1(1);
}

-- 
Configure issuemail: http://d.puremagic.com/issues/userprefs.cgi?tab=email
------- You are receiving this mail because: -------
March 14, 2013
http://d.puremagic.com/issues/show_bug.cgi?id=1528



--- Comment #28 from Martin Nowak <code@dawg.eu> 2013-03-14 15:55:08 PDT ---
(In reply to comment #26)

It's not about the polysemous literals.
What's irritating me is that a function call with conversion
is preferred over a function template instantiation with
exact arguments.

int f3(long) { return 1; }
int f3(T)(T) { return 2; }

int v = 2;
f3(v);

MATCHexact / MATCHconvert vs.
MATCHconvert / MATCHexact

-- 
Configure issuemail: http://d.puremagic.com/issues/userprefs.cgi?tab=email
------- You are receiving this mail because: -------