www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - Partial template function specialization

reply Peter Alexander <peter.alexander.au gmail.com> writes:
Hey all,

I'm considering learning D at the moment, and one thing that has bothered me in
C++ is the lack of partial template function specializations. For example, you
can create something like this:

template <class Field, class V>
const Field norm(const V& v);

and you can specialize it:

template <>
const double norm(const double& d)
{ return d < 0.0 ? -d : d; }

but you can't partially specialize it:

template <class Field>
const Field norm(const Vector3<Field>& v)
{ /* return sqrt( ... ) */ }

Unless I'm mistaken...

Also, while I'm here. Does D have any macro support? I know it doesn't have
pre-processor macros, but something like Nemerle's macros would be really,
really nice.

Thanks in advance.
Aug 19 2009
next sibling parent reply "Simen Kjaeraas" <simen.kjaras gmail.com> writes:
Peter Alexander wrote:

 Hey all,

 I'm considering learning D at the moment, and one thing that has  
 bothered me in C++ is the lack of partial template function  
 specializations.
T foo( T, U )( U value ) {...} template fooPartial( T ) { alias foo!( T, int ) fooPartial; } This may or may not have been what you want.
 Also, while I'm here. Does D have any macro support? I know it doesn't  
 have pre-processor macros, but something like Nemerle's macros would be  
 really, really nice.
Macros are currently scheduled for D3. In the meantime, you can do just about anything with string mixins and CTFE. -- Simen
Aug 20 2009
parent reply Peter Alexander <peter.alexander.au gmail.com> writes:
Simen Kjaeraas Wrote:
 
 T foo( T, U )( U value ) {...}
 
 template fooPartial( T ) {
    alias foo!( T, int ) fooPartial;
 }
 
 This may or may not have been what you want.
Not quite sure what's going on there, but it doesn't look like what I want. I want a general function: T foo(T, U)(U value) and one specialized for when U = Vector3!(T) Also, it's important that the original and the specialization have the same function name, otherwise it's not really generic at all.
 Macros are currently scheduled for D3. In the meantime, you can do just
 about anything with string mixins and CTFE.
Cool. Is there any sort of ETA on D3?
Aug 20 2009
next sibling parent "Lars T. Kyllingstad" <public kyllingen.NOSPAMnet> writes:
Peter Alexander wrote:
 Simen Kjaeraas Wrote:
 Macros are currently scheduled for D3. In the meantime, you can do just
 about anything with string mixins and CTFE.
Cool. Is there any sort of ETA on D3?
Man, we just got the ETA on D2... :) -Lars
Aug 20 2009
prev sibling next sibling parent bearophile <bearophileHUGS lycos.com> writes:
Peter Alexander:

 I want a general function:
 T foo(T, U)(U value)
 and one specialized for when U = Vector3!(T)
 Also, it's important that the original and the specialization have the same
function name, otherwise it's not really generic at all.
I think that was partial specialization, but the name was indeed different. Templates once instantiated produce all different functions, so when you instantiate them you have the same gains coming from partial instantiation. If you want a single name for both templates you can probably do that too, you may need a third template with a different type that a compile-time uses one or the other version of the template, in D2 you can also use template constraints. If you show me your use case there's probably some way to solve your problem, I have found D templates quite flexible.
Cool. Is there any sort of ETA on D3?<
It may be possible that some of my words have changed Walter's mind, so macros will not be seen in D. Bye, bearophile
Aug 20 2009
prev sibling parent Lutger <lutger.blijdestijn gmail.com> writes:
You can also do this with template constraints in D2:

template foo(T, U)
    if ( is(T == int) )
{
    void foo(T t, U u)
    {
	//t is int
    }
}

template foo(T, U)
    if ( is(T == string) )
{
    void foo(T t, U u)
    {
	//t is string
    }
}


IFTI still works here: foo("bla", 1) and foo(1,1) are both valid

You can do almost anything in the if condition (constraint) that can 
evaluate to bool at compile time. See std.traits and the __traits keywords 
for useful stuff.
Aug 20 2009
prev sibling next sibling parent reply "Lars T. Kyllingstad" <public kyllingen.NOSPAMnet> writes:
Peter Alexander wrote:
 Hey all,
 
 I'm considering learning D at the moment, and one thing that has bothered me
in C++ is the lack of partial template function specializations. For example,
you can create something like this:
 
 template <class Field, class V>
 const Field norm(const V& v);
 
 and you can specialize it:
 
 template <>
 const double norm(const double& d)
 { return d < 0.0 ? -d : d; }
 
 but you can't partially specialize it:
 
 template <class Field>
 const Field norm(const Vector3<Field>& v)
 { /* return sqrt( ... ) */ }
 
 Unless I'm mistaken...
You've come to the right place. D's template specialisation is very powerful, and when combined with implicit function template instantiation (IFTI) it makes for really beautiful code. Disclaimer: You didn't say whether you use D1 or D2, but I use D2, so I'll give my answer in D2 code. It is highly likely it will also work in D1. First of all, I don't know how it is in C++, but in D you rarely write function declarations without definitions. So unless you have a very general function body for your "general case", I'd simply drop it. If you have, the general case looks like this: Field norm(Field, V)(ref V v) { ... } // To call it: SomeDoublePrecisionVector v = ...; double n = norm!(double, SomeDoublePrecisionVector)(v); Actually, because of IFTI, you can probably call it like double n = norm!(double)(v); but there is a chance that the compiler will find it too much like the partially specialised case below. The completely specialised case will look like this: double norm()(double d) { return d < 0.0 ? -d : d; } // To call it: double n = norm(-3.0); Note that in the not-too-far future it is likely that non-templated functions will be allowed to overload against templated functions. When that happens, you can drop the first set of parentheses in the declaration. I would write the partially specialised case like this: Field norm(Field)(ref Vector3!(Field) v) { ... } // To call it: Vector3!(real) myVector; real n = norm(myVector); Yes, the compiler is smart enough to extract the Field from the Vector3!(Field) type. :) Because of IFTI you don't even have to specify it when calling norm(). In the above I have at least tried to stay D1 compatible. In D2 you can (arguably, of course) beautify your code a bit by writing Vector3!Float and so on. The parentheses are only needed when there are several template parameters. For more info, check out http://www.digitalmars.com/d/2.0/template.html -Lars
Aug 20 2009
next sibling parent "Lars T. Kyllingstad" <public kyllingen.NOSPAMnet> writes:
Lars T. Kyllingstad wrote:
 First of all, I don't know how it is in C++, but in D you rarely write 
 function declarations without definitions.
What I meant was: I don't know how common *templated* function declarations are. I know C++ programmers tend to put the declaration in one place and the definition in an entirely different place. One of the annoying things of C++ that D fixes, IMHO. -Lars
Aug 20 2009
prev sibling parent reply Peter Alexander <peter.alexander.au gmail.com> writes:
Lars T. Kyllingstad Wrote:

 Disclaimer: You didn't say whether you use D1 or D2, but I use D2, so 
 I'll give my answer in D2 code. It is highly likely it will also work in D1.
I'm using neither :) I'm just considering learning at the moment.
 First of all, I don't know how it is in C++, but in D you rarely write 
 function declarations without definitions. So unless you have a very 
 general function body for your "general case", I'd simply drop it. If 
 you have, the general case looks like this:
 
  <snip>
 
 For more info, check out http://www.digitalmars.com/d/2.0/template.html
 
 -Lars
Excellent! Thanks a lot. I was hoping that D could overcome this problem. Ah, one (maybe) final question: Is there an equivalent to friends in D (didn't see any in the docs)? If so, do they work with templates easily? In my style of programming, I very rarely use member functions (I think they are an atrocity in language design), so I create global functions for almost everything, and when they need to access to private members, I have the class declare the function as a friend. Does D support my style of programming? Here's a concrete example of something I'd like to do (pseudocode): class Foo { private int x; friend globalFun; } class Bar { private int y; friend globalFun; } void globalFun(ref Foo foo, ref Bar bar) { foo.x = bar.y; } Is there anything like this in D? Export sounds like the right thing, but can that be used in the example above, assuming that Foo and Bar are in separate modules?
Aug 20 2009
next sibling parent "Steven Schveighoffer" <schveiguy yahoo.com> writes:
On Thu, 20 Aug 2009 10:22:00 -0400, Peter Alexander  
<peter.alexander.au gmail.com> wrote:

 Lars T. Kyllingstad Wrote:

 Disclaimer: You didn't say whether you use D1 or D2, but I use D2, so
 I'll give my answer in D2 code. It is highly likely it will also work  
 in D1.
I'm using neither :) I'm just considering learning at the moment.
 First of all, I don't know how it is in C++, but in D you rarely write
 function declarations without definitions. So unless you have a very
 general function body for your "general case", I'd simply drop it. If
 you have, the general case looks like this:

  <snip>

 For more info, check out http://www.digitalmars.com/d/2.0/template.html

 -Lars
Excellent! Thanks a lot. I was hoping that D could overcome this problem. Ah, one (maybe) final question: Is there an equivalent to friends in D (didn't see any in the docs)? If so, do they work with templates easily?
The module system is the way to get comparable, if not equivalent, behavior. Any functions or classes declared in the same module are automatically friends with eachother. The idea behind it is that a single module is generally developed as a group of related items, and so the functions existing in the same module usually know the internals of the objects inside the module. Plus the author of such functions obviously has access to the source code, and generally is the author of the objects.
 In my style of programming, I very rarely use member functions (I think  
 they are an atrocity in language design), so I create global functions  
 for almost everything, and when they need to access to private members,  
 I have the class declare the function as a friend.

 Does D support my style of programming?
Yes, global functions declared in the same module of the class have full access to private variables.
 Here's a concrete example of something I'd like to do (pseudocode):

 class Foo { private int x; friend globalFun; }
 class Bar { private int y; friend globalFun; }

 void globalFun(ref Foo foo, ref Bar bar) { foo.x = bar.y; }

 Is there anything like this in D? Export sounds like the right thing,  
 but can that be used in the example above, assuming that Foo and Bar are  
 in separate modules?
You would have to put Foo and Bar in the same module along with globalFun, or declare their members as package, and put their modules in the same package. -Steve
Aug 20 2009
prev sibling next sibling parent Bill Baxter <wbaxter gmail.com> writes:
On Thu, Aug 20, 2009 at 7:22 AM, Peter
Alexander<peter.alexander.au gmail.com> wrote:
 Lars T. Kyllingstad Wrote:

 Disclaimer: You didn't say whether you use D1 or D2, but I use D2, so
 I'll give my answer in D2 code. It is highly likely it will also work in=
D1.
 I'm using neither :) =A0I'm just considering learning at the moment.


 First of all, I don't know how it is in C++, but in D you rarely write
 function declarations without definitions. So unless you have a very
 general function body for your "general case", I'd simply drop it. If
 you have, the general case looks like this:

 =A0<snip>

 For more info, check out http://www.digitalmars.com/d/2.0/template.html

 -Lars
Excellent! Thanks a lot. I was hoping that D could overcome this problem. Ah, one (maybe) final question: Is there an equivalent to friends in D (didn't see any in the docs)? If s=
o, do they work with templates easily?
 In my style of programming, I very rarely use member functions (I think t=
hey are an atrocity in language design), so I create global functions for a= lmost everything, and when they need to access to private members, I have t= he class declare the function as a friend.
 Does D support my style of programming?
Instead of friend, in D everything within one file (=3D=3Done module) has access to everything else in that same file/module. So you can use your style, as long as you put the global functions in the same module as the classes operated on.
 Here's a concrete example of something I'd like to do (pseudocode):

 class Foo { private int x; friend globalFun; }
 class Bar { private int y; friend globalFun; }

 void globalFun(ref Foo foo, ref Bar bar) { foo.x =3D bar.y; }

 Is there anything like this in D? Export sounds like the right thing, but=
can that be used in the example above, assuming that Foo and Bar are in se= parate modules? I don't think export has anything to do with it. --bb
Aug 20 2009
prev sibling parent Jarrett Billingsley <jarrett.billingsley gmail.com> writes:
On Thu, Aug 20, 2009 at 10:34 AM, Bill Baxter<wbaxter gmail.com> wrote:
 On Thu, Aug 20, 2009 at 7:22 AM, Peter
 Alexander<peter.alexander.au gmail.com> wrote:
 Lars T. Kyllingstad Wrote:
 In my style of programming, I very rarely use member functions (I think =
they are an atrocity in language design), so I create global functions for = almost everything, and when they need to access to private members, I have = the class declare the function as a friend.
 Does D support my style of programming?
Instead of friend, in D everything within one file (=3D=3Done module) has access to everything else in that same file/module. So you can use your style, as long as you put the global functions in the same module as the classes operated on.
Alternatively, you can mark the data members 'package', and then any functions in the same package can access them. But keep in mind that 'package' is limited in that you can't access those members from sub-packages, meaning you are forced into a flat package hierarchy.
Aug 20 2009
prev sibling parent Sato. E. <sato nomail.com> writes:
Peter Alexander Wrote:

 Hey all,
 
 I'm considering learning D at the moment, and one thing that has bothered me
in C++ is the lack of partial template function specializations. For example,
you can create something like this:
 template <class Field>
 const Field norm(const Vector3<Field>& v)
 { /* return sqrt( ... ) */ }
 Thanks in advance.
Field norm(Field, V)(V v) { ... } Field norm(Field, V : Vector3!(Field))(ref V v) { ... } --- auto v = new Vector3!(float) norm!(float)(v)
Aug 20 2009