Thread overview
Suggestion: function template overloading
Aug 29, 2006
Kristian
Aug 29, 2006
Sean Kelly
Aug 29, 2006
Kristian
Aug 29, 2006
Sean Kelly
Aug 29, 2006
Kristian
Aug 29, 2006
Walter Bright
August 29, 2006
It would be very nice if you could overload function templates as you can in C++. Here is what I mean:

void f(T)(T val) {...}

void f(int val) {...}  //error: conflicts with the template function

It would allow you to write special cases for types that need it.


Here is an example:

int CMP__compare(T)(T left, T right) {
    return(left < right ? -1 : (left > right ? 1 : 0));
}

class Array(T) {
    typedef int function(T, T) compare_func_t;

    final int findOrdered(T obj) {
        return(findOrdered(CMP__compare, obj));
    }
    int findOrdered(compare_func_t cmp_func, T obj) {
        //use 'cmp_func' with binary search to find 'obj' from the array...
    }

    final void sort() {
        sort(CMP__compare);
    }
    void sort(compare_func_t cmp_func) {...};
}

One could ask why not to compare 'obj' directly in 'findOrdered()', i.e. why to wrap the comparision inside a function template. This way you can easily affect how 'obj' is searched. For example:

struct Stru {
    int a, b;
}

int CMP__compare(Stru left, Stru right) {
    if(left.a == -1 || right.a == -1)
        return(CMP__compare(left.b, right.b));
    else
        return(CMP__compare(left.a, right.a));
}

int CMP__compareInv(T)(T left, T right) {
    return(-CMP__compare(left, right));
}

void func() {
    int pos;
    Array!(Stru) a;
    Stru s;

    ...
    pos = a.findOrdered(s);
    ...
    a.sort(CMP__compareInv);
}
August 29, 2006
Kristian wrote:
> 
> It would be very nice if you could overload function templates as you can in C++. Here is what I mean:
> 
> void f(T)(T val) {...}
> 
> void f(int val) {...}  //error: conflicts with the template function
> 
> It would allow you to write special cases for types that need it.

void f(T)(T val) {}
void f()(int val) {}


Sean
August 29, 2006
On Tue, 29 Aug 2006 21:04:53 +0300, Sean Kelly <sean@f4.ca> wrote:

> Kristian wrote:
>>  It would be very nice if you could overload function templates as you can in C++. Here is what I mean:
>>  void f(T)(T val) {...}
>>  void f(int val) {...}  //error: conflicts with the template function
>>  It would allow you to write special cases for types that need it.
>
> void f(T)(T val) {}
> void f()(int val) {}
>
>
> Sean

Ah, thanks! I missed _that_ one completely... :/

But now I can't get the following to work:

bool equal(T)(T l, T r) {
    return l == r;
}
bool equal()(Foo l, Foo r) {
    return l.m_val == r.m_val;
}

class Foo {
    int m_val = 0;
}

class Bar(T) {
    this() {
        m_val = new T;
    }

    bool eq(T obj) {
        return(equal(m_val, obj));  //error: matches more than one template, equal(T) and equal()
    }

    T m_val;
}

void main() {
    Bar!(Foo) bar = new Bar!(Foo);
    Foo foo = new Foo;

    printf("%d\n", bar.eq(foo));
}

It seems that 'binding' is done when 'Bar' is compiled, not when 'bar' variable is declared.
August 29, 2006
Kristian wrote:
> On Tue, 29 Aug 2006 21:04:53 +0300, Sean Kelly <sean@f4.ca> wrote:
> 
>> Kristian wrote:
>>>  It would be very nice if you could overload function templates as you can in C++. Here is what I mean:
>>>  void f(T)(T val) {...}
>>>  void f(int val) {...}  //error: conflicts with the template function
>>>  It would allow you to write special cases for types that need it.
>>
>> void f(T)(T val) {}
>> void f()(int val) {}
>>
>>
>> Sean
> 
> Ah, thanks! I missed _that_ one completely... :/
> 
> But now I can't get the following to work:
> 
> bool equal(T)(T l, T r) {
>     return l == r;
> }
> bool equal()(Foo l, Foo r) {
>     return l.m_val == r.m_val;
> }
> 
> class Foo {
>     int m_val = 0;
> }
> 
> class Bar(T) {
>     this() {
>         m_val = new T;
>     }
> 
>     bool eq(T obj) {
>         return(equal(m_val, obj));  //error: matches more than one template, equal(T) and equal()
>     }
> 
>     T m_val;
> }
> 
> void main() {
>     Bar!(Foo) bar = new Bar!(Foo);
>     Foo foo = new Foo;
> 
>     printf("%d\n", bar.eq(foo));
> }
> 
> It seems that 'binding' is done when 'Bar' is compiled, not when 'bar' variable is declared.

In this case, it should choose equal()( Foo ... ) over equal(T)( T ...) because the Foo overload is the most specialized for the supplied parameters.  Unfortunately, implicit template support in DMD is still pretty thin so you're probably running into a compiler limitation rather than a problem with the spec.  Instead of:

equal()( Foo l, Foo r )

try:

equal( T : Foo )( Foo l, Foo r )

and see what happens.  I've found that with a bit of experimentation (and perhaps some wrapper code) you can usually get ITI to work as desired, and simply remove the work-around code as DMD improves.


Sean
August 29, 2006
Sean Kelly wrote:
> Kristian wrote:
>>
>> It would be very nice if you could overload function templates as you can in C++. Here is what I mean:
>>
>> void f(T)(T val) {...}
>>
>> void f(int val) {...}  //error: conflicts with the template function
>>
>> It would allow you to write special cases for types that need it.
> 
> void f(T)(T val) {}
> void f()(int val) {}

Or:
	void f(T:int)(T val) {}

The trouble is that D has problems with specialization, but that's a compiler problem.

C++ has complex rules regarding mixing functions and function templates with the same name. D just sidesteps the problem by disallowing that. There's no loss of functionality.

I think the reason C++ did that was because the template design originally didn't allow template specialization, and when it did, it was stuck with the legacy code.
August 29, 2006
On Tue, 29 Aug 2006 21:44:35 +0300, Sean Kelly <sean@f4.ca> wrote:
> Kristian wrote:
>> On Tue, 29 Aug 2006 21:04:53 +0300, Sean Kelly <sean@f4.ca> wrote:
>>
>>> Kristian wrote:
>>>>  It would be very nice if you could overload function templates as you can in C++. Here is what I mean:
>>>>  void f(T)(T val) {...}
>>>>  void f(int val) {...}  //error: conflicts with the template function
>>>>  It would allow you to write special cases for types that need it.
>>>
>>> void f(T)(T val) {}
>>> void f()(int val) {}
>>>
>>>
>>> Sean
>>  Ah, thanks! I missed _that_ one completely... :/
>>  But now I can't get the following to work:
>>  bool equal(T)(T l, T r) {
>>     return l == r;
>> }
>> bool equal()(Foo l, Foo r) {
>>     return l.m_val == r.m_val;
>> }
>>  class Foo {
>>     int m_val = 0;
>> }
>>  class Bar(T) {
>>     this() {
>>         m_val = new T;
>>     }
>>      bool eq(T obj) {
>>         return(equal(m_val, obj));  //error: matches more than one template, equal(T) and equal()
>>     }
>>      T m_val;
>> }
>>  void main() {
>>     Bar!(Foo) bar = new Bar!(Foo);
>>     Foo foo = new Foo;
>>      printf("%d\n", bar.eq(foo));
>> }
>>  It seems that 'binding' is done when 'Bar' is compiled, not when 'bar' variable is declared.
>
> In this case, it should choose equal()( Foo ... ) over equal(T)( T ...) because the Foo overload is the most specialized for the supplied parameters.  Unfortunately, implicit template support in DMD is still pretty thin so you're probably running into a compiler limitation rather than a problem with the spec.  Instead of:
>
> equal()( Foo l, Foo r )
>
> try:
>
> equal( T : Foo )( Foo l, Foo r )
>
> and see what happens.  I've found that with a bit of experimentation (and perhaps some wrapper code) you can usually get ITI to work as desired, and simply remove the work-around code as DMD improves.
>
>
> Sean


Ok, thanks again!