December 27, 2012
http://d.puremagic.com/issues/show_bug.cgi?id=1528


Kenji Hara <k.hara.pg@gmail.com> changed:

           What    |Removed                     |Added
----------------------------------------------------------------------------
           Keywords|                            |pull


--- Comment #9 from Kenji Hara <k.hara.pg@gmail.com> 2012-12-27 01:34:31 PST ---
https://github.com/D-Programming-Language/dmd/pull/1409

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


Kenji Hara <k.hara.pg@gmail.com> changed:

           What    |Removed                     |Added
----------------------------------------------------------------------------
           Keywords|pull                        |


--- Comment #10 from Kenji Hara <k.hara.pg@gmail.com> 2013-02-24 21:32:10 PST ---
(In reply to comment #9)
> https://github.com/D-Programming-Language/dmd/pull/1409

By implementing it, I found some corner cases. How should these behave?

int f1(int a, double=10) { return 1; }
int f1(int a, string="") { return 2; }

int f2(T:int)(T b, double=10) { return 1; }
int f2(T:int)(T b, string="") { return 2; }

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

// vs specialized parameter
int f4(int a) { return 1; }
int f4(T:int)(T b) { return 2; }

// vs deduced parameter + template constraint (1)
int f5(int a) { return 1; }
int f5(T)(T b) if (is(T == int)) { return 2; }

// vs deduced parameter + template constraint (2)
int f6(int a) { return 1; }
int f6(T)(T b) if (is(T : int)) { return 2; }

void main()
{
    f1(1);  // ambiguous error
    f1(1L); // ambiguous error

    f2(1);  // ambiguous error
    f2(1L); // ambiguous error

    f3(1);  // ?
    f3(1L); // ?

    f4(1);  // ?
    f4(1L); // ?

    f5(1);  // ?
    f5(1L); // ?

    f6(1);  // ?
    f6(1L); // ?
}

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



--- Comment #11 from Walter Bright <bugzilla@digitalmars.com> 2013-02-24 21:54:47 PST ---
(In reply to comment #10)
>     f3(1);  // 1
>     f3(1L); // 2
> 
>     f4(1);  // ambiguous
>     f4(1L); // ambiguous
> 
>     f5(1);  // 1
>     f5(1L); // 1
> 
>     f6(1);  // 1
>     f6(1L); // 2
> }

The more specialized overload always wins.

The constraint is not considered when evaluating which is "more specialized". (Because in general we cannot evaluate that.) The constraint only determines if an overload is to be considered - it does not determine ordering.

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



--- Comment #12 from Kenji Hara <k.hara.pg@gmail.com> 2013-02-24 22:30:26 PST ---
(In reply to comment #11)
> The more specialized overload always wins.
> 
> The constraint is not considered when evaluating which is "more specialized". (Because in general we cannot evaluate that.) The constraint only determines if an overload is to be considered - it does not determine ordering.

Thanks for quickly answer. So, the resolution result of f5 and f6 should be same as f3, because they are identical when hide their constraints. Right?

But, there is still questionable. How to calculate "The more specialized overload" between function template and non-template one? For example, try to consider case for f3(1). That is:

1. Normal function version f3(int) will match exactly to one int argument.
2. Function template version will deduce T <- int, and then instantiated
function f3!(int) == void f3(int) will match _exactly_ to one int argument.

But, in general, template version is less specialized than non-template version. So, there is something necessary for ordering.

---
Consider one another case for f4(1L). That is:

1. Normal function will match to one long argument with conversion
(MATCHconvert).
2. Function template version will deduce T <- long and then instantiated
function f4!long will match exactly to one long argument.

Which is specialized? In general, template version would be intended to pick up non-exact matching for generic cases. But, as far as I infer from current dmd implementation, f4(1L) will be ambiguous (template type parameter deduction without specialization always be MATCHconvert).

Therefore, I'd ask question again to Walter: how does above cases behave?

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


timon.gehr@gmx.ch changed:

           What    |Removed                     |Added
----------------------------------------------------------------------------
                 CC|                            |timon.gehr@gmx.ch


--- Comment #13 from timon.gehr@gmx.ch 2013-02-25 02:15:54 PST ---
(In reply to comment #12)
> ...
> 
> Therefore, I'd ask question again to Walter: how does above cases behave?

I have implemented it in accordance with TDPL, and the following behaviour results:

int f1(int a, double=10) { return 1; }
int f1(int a, string="") { return 2; }

int f2(T:int)(T b, double=10) { return 1; }
int f2(T:int)(T b, string="") { return 2; }

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

// vs specialized parameter
int f4(int a) { return 1; }
int f4(T:int)(T b) { return 2; }

// vs deduced parameter + template constraint (1)
int f5(int a) { return 1; }
int f5(T)(T b) if (is(T == int)) { return 2; }

// vs deduced parameter + template constraint (2)
int f6(int a) { return 1; }
int f6(T)(T b) if (is(T : int)) { return 2; }

void main(){
    f1(1);  // error: ambiguous
    f1(1L); // error: ambiguous

    f2(1);  // error: ambiguous
    f2(1L); // error: no match

    static assert(f3(1)==1);
    static assert(f3(1L)==2);

    static assert(f4(1)==1);
    static assert(f4(1L)==1);

    static assert(f5(1)==1);
    static assert(f5(1L)==1);

    static assert(f6(1)==1);
    static assert(f6(1L)==1);
}

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


monarchdodra@gmail.com changed:

           What    |Removed                     |Added
----------------------------------------------------------------------------
                 CC|                            |monarchdodra@gmail.com


--- Comment #14 from monarchdodra@gmail.com 2013-02-27 04:39:08 PST ---
(In reply to comment #13)
> I have implemented it in accordance with TDPL, and the following behaviour results:
> 
> // vs deduced parameter + template constraint (2)
> int f6(int a) { return 1; }
> int f6(T)(T b) if (is(T : int)) { return 2; }
> 
> void main(){
>     static assert(f6(1)==1);
>     static assert(f6(1L)==1);
> }

How does that work though, because here, you statically know that 1L will fit in your int. But what about:

static assert(f6(1L) == 1);
static assert(f6(ulong.max) == 2); // (a) ???

ulong ul = runtime();
static assert(f6(ul) == 2);        // (b) ???

How would these resolve?

I am not really comfortable with the fact that a call can statically resolve to two different functions depending on the static information of the *value* of a parameter:

int f7(ubyte a) { return 1; }
int f7(T)(T b) if (is(T : int)) { return 2; }

void main(){
    static assert(f6(200u)==1); //Calls first
    static assert(f6(400u)==2); //Calls second (!?)

    //Run-time variable with TDPL-like range knowledge
    uint a = 400;
    static assert(f6(a) == 2); //Calls second  ?
    a = 200;
    static assert(f6(a) == 1); //But now calls first !?
}

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



--- Comment #15 from timon.gehr@gmx.ch 2013-02-27 06:29:43 PST ---
(In reply to comment #14)
> ...
> 
> static assert(f6(1L) == 1);
> static assert(f6(ulong.max) == 2); // (a) ???
> 

No match.

> ulong ul = runtime();
> static assert(f6(ul) == 2);        // (b) ???
> 

No match.

> How would these resolve?
> 
> I am not really comfortable with the fact that a call can statically resolve to two different functions depending on the static information of the *value* of a parameter:
> 

Well, that is how the language is specified.


int f8(byte){ return 1; }
int f8(long){ return 2; }

void main(){
    static assert(f8(1)==1); // calls first
    static assert(f8(256)==2); // calls second
    int x=1;
    f8(x); // calls second
}

> int f7(ubyte a) { return 1; }
> int f7(T)(T b) if (is(T : int)) { return 2; }
> 
> void main(){
>     static assert(f6(200u)==1); //Calls first

No, calls second.

>     static assert(f6(400u)==2); //Calls second (!?)
> 

Yes.

>     //Run-time variable with TDPL-like range knowledge
>     uint a = 400;

Knowledge lost here.

>     static assert(f6(a) == 2); //Calls second  ?
>     a = 200;

Ditto.

>     static assert(f6(a) == 1); //But now calls first !?
> }

-- 
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 #16 from Kenji Hara <k.hara.pg@gmail.com> 2013-02-28 20:46:30 PST ---
(In reply to comment #13)
> // vs specialized parameter
> int f4(int a) { return 1; }
> int f4(T:int)(T b) { return 2; }

>     static assert(f4(1)==1);

Just only this is wrong. f4(T:int) is specialized to int argument, so f4(1)
could match both normal function version and template version *with the same
extent*. Then it will be ambiguous.

>     static assert(f4(1L)==1);

Ok. f4(T:int) cannot instantiate with T==long, so first version will be called.


(In reply to comment #15)
> (In reply to comment #14)
> > ...
> > 
> > static assert(f6(1L) == 1);
> > static assert(f6(ulong.max) == 2); // (a) ???
> > 
> 
> No match.
> 
> > ulong ul = runtime();
> > static assert(f6(ul) == 2);        // (b) ???
> > 
> 
> No match.

Both (a) and (b) should be "no match", but with my experimental change, (a)
wrongly matches to int. I found an another bug in there, and filed it as bug
9617.


Current test case results with my pull request: https://github.com/D-Programming-Language/dmd/pull/1409

is:
--------
int f1(int a, double=10) { return 1; }
int f1(int a, string="") { return 2; }

int f2(T:int)(T b, double=10) { return 1; }
int f2(T:int)(T b, string="") { return 2; }

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

// vs specialized parameter
int f4(int a) { return 1; }
int f4(T:int)(T b) { return 2; }

// vs deduced parameter + template constraint (1)
int f5(int a) { return 1; }
int f5(T)(T b) if (is(T == int)) { return 2; }

// vs deduced parameter + template constraint (2)
int f6(int a) { return 1; }
int f6(T)(T b) if (is(T : int)) { return 2; }

// vs nallowing conversion
int f7(ubyte a) { return 1; }
int f7(T)(T b) if (is(T : int)) { return 2; }

void main()
{
    static assert(!__traits(compiles, f1(1)));  // ambiguous
    static assert(!__traits(compiles, f1(1L))); // ambiguous

    static assert(!__traits(compiles, f2(1)));  // ambiguous
    static assert(!__traits(compiles, f2(1L))); // no match

    assert(f3(1) == 1);
    assert(f3(1L) == 2);

    static assert(!__traits(compiles, f4(1)));
    assert(f4(1L) == 1);

    assert(f5(1) == 1);
    assert(f5(1L) == 1);

    assert(f6(1) == 1);
    assert(f6(1L) == 1);
    static assert(!__traits(compiles, f6(ulong.max))); // no match
                                          // needs to fix bug 9617
    ulong ulval = 1;
    static assert(!__traits(compiles, f6(ulval)));     // no match

    assert(f7(200u) == 2);
    assert(f7(400u) == 2);
    uint uival = 400;   // TDPL-like range knowledge lost here.
    assert(f7(uival) == 2);
    a = 200;            // Ditto.
    assert(f7(uival) == 2);
}
--------

I welcome more complicated test case.

-- 
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


Martin Nowak <code@dawg.eu> changed:

           What    |Removed                     |Added
----------------------------------------------------------------------------
                 CC|                            |code@dawg.eu


--- Comment #17 from Martin Nowak <code@dawg.eu> 2013-03-01 02:19:23 PST ---
> 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.

-- 
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 #18 from timon.gehr@gmx.ch 2013-03-01 03:15:40 PST ---
(In reply to comment #17)
> > template type parameter deduction without specialization always be MATCHconvert
> 
> AFAIK this is a kludgy implementation detail

It is a bug.

> to make specialization work.

Why wouldn't they work otherwise?

> 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.

There already is a level between them (conversion to const.)

Anyway, I do not see why another level would be required, or even helpful in any way.

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