www.digitalmars.com         C & C++   DMDScript  

digitalmars.D - class template members (bug or feature?)

reply Sean Kelly <sean f4.ca> writes:
When trying to compile this code:

class MyClass {
public:
template fn( T ) { int fn( T t ) { return 1; } }
int fn( int t ) { return 2; }
}

I get this error:

test3.d(4): function fn conflicts with MyClass.fn(T) at test3.d(3)

Why is there a conflict?  The template isn't being instantiated, and even if it
were instantiated for type int the calling conventions are different so I
wouldn't expect to see this error.  Both these problems go away if I change the
name of the template or function so they don't conflict, but I'm still curious
about whether this is intended behavior.


Sean
Jun 15 2004
parent reply Norbert Nemec <Norbert.Nemec gmx.de> writes:
Sean Kelly wrote:

 When trying to compile this code:
 
 class MyClass {
 public:
 template fn( T ) { int fn( T t ) { return 1; } }
 int fn( int t ) { return 2; }
 }
 
 I get this error:
 
 test3.d(4): function fn conflicts with MyClass.fn(T) at test3.d(3)

The function fn conflicts with the template fn. Probably, what you want to do is specialization: class MyClass { template fn( T ) { int fn( T t ) { return 1; } } template fn( T: int ) } { int fn( int t ) { return 2; } } } (hope this compiles - didn't check it. Just read it from the specs) In any case, I fear, what you are trying to do will not work, since a template cannot be used to add public (i.e. virtual) functions to a class. In any case, it has to be understood that a template is a language object - in this case with the name fn - even if it is not instantiated. It will be part of the namespace and can therefore conflict with other objects. The name of the function inside the template (which is identical in this case) is irrelevant in that respect.
Jun 15 2004
parent reply Sean Kelly <sean f4.ca> writes:
In article <cani18$nh$1 digitaldaemon.com>, Norbert Nemec says...
In any case, I fear, what you are trying to do will not work, since a
template cannot be used to add public (i.e. virtual) functions to a class.

Don't care if they can be made virtual. In this case I'm using private templates and aliasing them for various types in order to avoid duplicated code for a set of overloaded functions.
In any case, it has to be understood that a template is a language object -
in this case with the name fn - even if it is not instantiated. It will be
part of the namespace and can therefore conflict with other objects. The
name of the function inside the template (which is identical in this case)
is irrelevant in that respect.

Certainly. Perhaps the problem is that I'm expecting templates to work as they do in C++, where a template functions are evaluated during overload resolution. In D, template functions actually define a separate namespace and it's this namespace that's conflicting with a function name in the same scope. I'll admit I'd be overjoyed if there were a shorthand way to write template functions similar to how class definitions can omit the "template" keyword--the current mechanism seems a bit clunky. But I suppose the shorthand used by template classes could be awkward to parse, as it would effectively result in a function with two separate parameter sets. Sean
Jun 15 2004
parent reply Norbert Nemec <Norbert.Nemec gmx.de> writes:
Sean Kelly wrote:

 In article <cani18$nh$1 digitaldaemon.com>, Norbert Nemec says...
In any case, I fear, what you are trying to do will not work, since a
template cannot be used to add public (i.e. virtual) functions to a class.

Don't care if they can be made virtual. In this case I'm using private templates and aliasing them for various types in order to avoid duplicated code for a set of overloaded functions.
In any case, it has to be understood that a template is a language object
- in this case with the name fn - even if it is not instantiated. It will
be part of the namespace and can therefore conflict with other objects.
The name of the function inside the template (which is identical in this
case) is irrelevant in that respect.

Certainly. Perhaps the problem is that I'm expecting templates to work as they do in C++, where a template functions are evaluated during overload resolution. In D, template functions actually define a separate namespace and it's this namespace that's conflicting with a function name in the same scope. I'll admit I'd be overjoyed if there were a shorthand way to write template functions similar to how class definitions can omit the "template" keyword--the current mechanism seems a bit clunky. But I suppose the shorthand used by template classes could be awkward to parse, as it would effectively result in a function with two separate parameter sets.

I.e. "one parameter and one argument set". The usual wording in C++ is that functions have arguments while templates have parameters. Anyhow: I agree that template functions are not very well supported in D. A suitable shorthand would be really helpful (no idea what it might look like), but even more important: *implicit instantiation* - anyhow that topic has been chewed over often enough in the past...
Jun 16 2004
parent reply Sean Kelly <sean f4.ca> writes:
In article <caplqu$24l$2 digitaldaemon.com>, Norbert Nemec says...
Anyhow: I agree that template functions are not very well supported in D. A
suitable shorthand would be really helpful (no idea what it might look
like), but even more important: *implicit instantiation* - anyhow that
topic has been chewed over often enough in the past...

Yup. But just to be pedantic, I also tried this and was a bit surprised it failed: interface I { void fn( int ); } class C : I { template fnImpl(T) { void fnImpl( int ) {} } alias fnImpl!(int) fn; } with this error: test.d(5): class C 1interface function I.fn is not implemented Sean
Jun 16 2004
parent reply Hauke Duden <H.NS.Duden gmx.net> writes:
Sean Kelly wrote:
 In article <caplqu$24l$2 digitaldaemon.com>, Norbert Nemec says...
 
Anyhow: I agree that template functions are not very well supported in D. A
suitable shorthand would be really helpful (no idea what it might look
like), but even more important: *implicit instantiation* - anyhow that
topic has been chewed over often enough in the past...

Yup. But just to be pedantic, I also tried this and was a bit surprised it failed: interface I { void fn( int ); } class C : I { template fnImpl(T) { void fnImpl( int ) {} } alias fnImpl!(int) fn; } with this error: test.d(5): class C 1interface function I.fn is not implemented

For this kind of thing you need to mix-in the template: class C : I { template fnImpl(T) { void fn(int) {} } mixin fnImpl!(int); } Hauke
Jun 16 2004
parent reply Sean Kelly <sean f4.ca> writes:
In article <capo9l$6d9$1 digitaldaemon.com>, Hauke Duden says...
Sean Kelly wrote:
 In article <caplqu$24l$2 digitaldaemon.com>, Norbert Nemec says...
 
Anyhow: I agree that template functions are not very well supported in D. A
suitable shorthand would be really helpful (no idea what it might look
like), but even more important: *implicit instantiation* - anyhow that
topic has been chewed over often enough in the past...

Yup. But just to be pedantic, I also tried this and was a bit surprised it failed: interface I { void fn( int ); } class C : I { template fnImpl(T) { void fnImpl( int ) {} } alias fnImpl!(int) fn; } with this error: test.d(5): class C 1interface function I.fn is not implemented

For this kind of thing you need to mix-in the template: class C : I { template fnImpl(T) { void fn(int) {} } mixin fnImpl!(int); }

Thanks :) Now to see if you have an answer for what I'm really trying to do: interface I { void fn( int ); void fn( int* ); } class C( SomeT ) : I { template fnImpl(T) { int fn( int x ) { return fn( &x ); } } mixin fnImpl!(int); int fn( int* x ) { return 0; } } errors: test.d(6): class C 1interface function I.fn is not implemented test.d(6): class C 1interface function I.fn is not implemented test.d(7): function fn (int x) does not match argument types (int*) test.d(7): cannot implicitly convert int* to int Now obviously the overload resolution isn't looking outside the scope of fnImpl to find fn(float), but is this correct? It should be noted that if I make C a normal class rather than a template then I only get the first two errors. Adding 'public' doesn't help. Sean
Jun 16 2004
parent reply Hauke Duden <H.NS.Duden gmx.net> writes:
Sean Kelly wrote:
 In article <capo9l$6d9$1 digitaldaemon.com>, Hauke Duden says...
 
Sean Kelly wrote:

In article <caplqu$24l$2 digitaldaemon.com>, Norbert Nemec says...


Anyhow: I agree that template functions are not very well supported in D. A
suitable shorthand would be really helpful (no idea what it might look
like), but even more important: *implicit instantiation* - anyhow that
topic has been chewed over often enough in the past...

Yup. But just to be pedantic, I also tried this and was a bit surprised it failed: interface I { void fn( int ); } class C : I { template fnImpl(T) { void fnImpl( int ) {} } alias fnImpl!(int) fn; } with this error: test.d(5): class C 1interface function I.fn is not implemented

For this kind of thing you need to mix-in the template: class C : I { template fnImpl(T) { void fn(int) {} } mixin fnImpl!(int); }

Thanks :) Now to see if you have an answer for what I'm really trying to do: interface I { void fn( int ); void fn( int* ); } class C( SomeT ) : I { template fnImpl(T) { int fn( int x ) { return fn( &x ); } } mixin fnImpl!(int); int fn( int* x ) { return 0; } } errors: test.d(6): class C 1interface function I.fn is not implemented test.d(6): class C 1interface function I.fn is not implemented test.d(7): function fn (int x) does not match argument types (int*) test.d(7): cannot implicitly convert int* to int Now obviously the overload resolution isn't looking outside the scope of fnImpl to find fn(float), but is this correct? It should be noted that if I make C a normal class rather than a template then I only get the first two errors. Adding 'public' doesn't help.

Heh, I stumbled about this as well. Mixins work just like import does, i.e. functions from different modules/mixins don't overload with each other by default. In other words, the problem is that you have a function with the same name ("fn") in both the mixin template and the class. To get this to work you have to add an alias for the mixin fn to the class. I.e. something like this (hopefully the syntax is correct - I've never used alias much): mixin fnImpl!(int) mixFn; alias mixFn.fn fn; Hauke
Jun 16 2004
parent Sean Kelly <sean f4.ca> writes:
In article <capqje$a6f$1 digitaldaemon.com>, Hauke Duden says...
Heh, I stumbled about this as well. Mixins work just like import does, 
i.e. functions from different modules/mixins don't overload with each 
other by default. In other words, the problem is that you have a 
function with the same name ("fn") in both the mixin template and the class.

To get this to work you have to add an alias for the mixin fn to the 
class. I.e. something like this (hopefully the syntax is correct - I've 
never used alias much):

mixin fnImpl!(int) mixFn;
alias mixFn.fn fn;

Oops! I just noticed that my previous example had an error--the return types were causing the errors. In any case, it seems like you understood my true problem anyway. After some experimentation, I managed to get it all working using something like the following: typedef int type1; // fake type for the example typedef int type2; // fake type for the example typedef int type3; // fake type for the example interface I { public: int fn( type1 ); int fn( type2 ); int fn( type3 ); } template T( SomeT ) { public: template fnImpl( OtherT ) { int fn( OtherT x ) { type2 y; return this.fn( y ); } } mixin fnImpl!(type1) fnImpl1; alias fnImpl1.fn fn; mixin fnImpl!(type2) fnImpl2; alias fnImpl2.fn fn; int fn( type3 x ) { return 0; } } class C : I { mixin T!(int); } Giving the mixins separate names and adding the alias line was what solved the problem. And putting everything in yet another mixin was closer to what I'm actually doing so it was nice to see that work as well. I must say, there are quite a few hurdles to jump in order to do what I'd consider typical template function overloading. But at least it's possible so I can't really complain. Thanks again for the help. Sean
Jun 16 2004