www.digitalmars.com         C & C++   DMDScript  

digitalmars.D - generalising template specialisation

reply Thomas Kuehne <thomas-dloop kuehne.cn> writes:
-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1

I am going to use TemplateTypeParameterSpecialization in the samples
below, all the ideas apply to TemplateValueParameterSpecialization too.


Current specialisation:
#
# template A (T : SomeType) { /* ... */ }
#

Template A matches if T is implicitly convertible to SomeType.


How do you define a template that matches if T is a struct?
#
# template B (T) {
#    static if(is(T == struct)) {
#	/* ... */
#    } else {
#       static assert(0, "use a struct");
#    }
# }
# 

OK that works, though the error will be reported on the assert line
instead of the instantiation line. Now suppose someoneelse writes a
template with the same functionality that supports classes:

#
# template B (T) {
#    static if(is(T == class)) {
#	/* ... */
#    } else {
#       static assert(0, "use a class");
#    }
# }
# 

Err, won't work:
b2.d(1): template b2.B(T) conflicts with b1.B(T) at b1.d(1)

Solution 1: merge those templates
#
# template B (T) {
#    static if(is(T == class)) {
#	/* ... */
#    } else if(is(T == struct)) {
#	/* ... */
#    } else {
#       static assert(0, "use a class or struct");
#    }
# }
# 

Problem: Merging 2 templates having different licenses and maintainers
can become a nightmare.

Solution 2: use a meta template
#
# private import b1, b2;
#
# template B (T) {
#    static if(is(T == class)) {
#	alias b1.B!(T) B;
#    } else if(is(T == struct)) {
#	alias b2.B!(T) B;
#    } else {
#       static assert(0, "use a class or struct");
#    }
# }
#

Problem: This is a very brittle approach introducing an extra level
of indirection and will fail if someone writes a third template
supporting e.g. delegates.

Please lift the current limitation and support all constructs allowed by
StaticIfCondition in TemplateTypeParameterSpecialization too.

Rewriting the B templates:
#
# template B( T : is(T == class)) {
#    /* ... */
# }
#
# template B( T : is(T == struct)) {
#    /* ... */
# }
#

I'm not aware of any lexicographic issues or problems with existing
code.

Thomas


-----BEGIN PGP SIGNATURE-----

iD8DBQFFVgePLK5blCcjpWoRAozeAJ0XhdYhQpU5h+ShfE20pRDZlvaCgQCfdtw4
z+eb88EAvNdxM3UDyq4dwH0=
=7J4/
-----END PGP SIGNATURE-----
Nov 11 2006
next sibling parent Sean Kelly <sean f4.ca> writes:
Thomas Kuehne wrote:
 -----BEGIN PGP SIGNED MESSAGE-----
 Hash: SHA1
 
 I am going to use TemplateTypeParameterSpecialization in the samples
 below, all the ideas apply to TemplateValueParameterSpecialization too.
 
 
 Current specialisation:
 #
 # template A (T : SomeType) { /* ... */ }
 #
 
 Template A matches if T is implicitly convertible to SomeType.
 
 
 How do you define a template that matches if T is a struct?
 #
 # template B (T) {
 #    static if(is(T == struct)) {
 #	/* ... */
 #    } else {
 #       static assert(0, "use a struct");
 #    }
 # }
 # 
 
 OK that works, though the error will be reported on the assert line
 instead of the instantiation line.

This is where concept checking is really useful. However, you can overload on concepts in D using something like the following: struct ClassType {} struct StructType {} ... template TypeOf( T ) { static if( is( T == class ) ) alias ClassType TypeOf; else static if( is( T == struct ) ) alias StructType TypeOf; ... } template ClassTempl( T, Type : ClassType = TypeOf!(T) ) { // make sure the user didn't cheat static assert( is( Type == TypeOf!(T) ); ... } template StructTempl( T Type : StructType = TypeOf!(T) ) { // make sure the user didn't cheat static assert( is( Type == TypeOf!(T) ); ... } It's a bit messy, but it works. Sean
Nov 11 2006
prev sibling next sibling parent Bill Baxter <wbaxter gmail.com> writes:
Thomas Kuehne wrote:
 -----BEGIN PGP SIGNED MESSAGE-----
 Hash: SHA1
 
 I am going to use TemplateTypeParameterSpecialization in the samples
 below, all the ideas apply to TemplateValueParameterSpecialization too.
 
 
 Current specialisation:
 #
 # template A (T : SomeType) { /* ... */ }
 #
 
 Template A matches if T is implicitly convertible to SomeType.
 
 
 How do you define a template that matches if T is a struct?
 #
 # template B (T) {
 #    static if(is(T == struct)) {
 #	/* ... */
 #    } else {
 #       static assert(0, "use a struct");
 #    }
 # }
 # 
 
 OK that works, though the error will be reported on the assert line
 instead of the instantiation line. Now suppose someoneelse writes a
 template with the same functionality that supports classes:
 
 #
 # template B (T) {
 #    static if(is(T == class)) {
 #	/* ... */
 #    } else {
 #       static assert(0, "use a class");
 #    }
 # }
 # 
 
 Err, won't work:
 b2.d(1): template b2.B(T) conflicts with b1.B(T) at b1.d(1)
 
 Solution 1: merge those templates
 #
 # template B (T) {
 #    static if(is(T == class)) {
 #	/* ... */
 #    } else if(is(T == struct)) {
 #	/* ... */
 #    } else {
 #       static assert(0, "use a class or struct");
 #    }
 # }
 # 
 
 Problem: Merging 2 templates having different licenses and maintainers
 can become a nightmare.
 
 Solution 2: use a meta template
 #
 # private import b1, b2;
 #
 # template B (T) {
 #    static if(is(T == class)) {
 #	alias b1.B!(T) B;
 #    } else if(is(T == struct)) {
 #	alias b2.B!(T) B;
 #    } else {
 #       static assert(0, "use a class or struct");
 #    }
 # }
 #
 
 Problem: This is a very brittle approach introducing an extra level
 of indirection and will fail if someone writes a third template
 supporting e.g. delegates.
 
 Please lift the current limitation and support all constructs allowed by
 StaticIfCondition in TemplateTypeParameterSpecialization too.
 
 Rewriting the B templates:
 #
 # template B( T : is(T == class)) {
 #    /* ... */
 # }
 #
 # template B( T : is(T == struct)) {
 #    /* ... */
 # }
 #
 
 I'm not aware of any lexicographic issues or problems with existing
 code.
 
 Thomas

+1. Don't have much to add, but I agree that for serious libraries, 3rd party code needs to be able to add new specializations without modifying the source of the original. --bb
Nov 11 2006
prev sibling next sibling parent Sean Kelly <sean f4.ca> writes:
Thomas Kuehne wrote:
 
 Please lift the current limitation and support all constructs allowed by
 StaticIfCondition in TemplateTypeParameterSpecialization too.
 
 Rewriting the B templates:
 #
 # template B( T : is(T == class)) {
 #    /* ... */
 # }
 #
 # template B( T : is(T == struct)) {
 #    /* ... */
 # }
 #

By the way, in case it didn't seem like it in my other post, I would *love* to have a feature like this. It would be a reasonable substitute for concept checking in D. Sean
Nov 11 2006
prev sibling parent "Kristian Kilpi" <kjkilpi gmail.com> writes:
On Sat, 11 Nov 2006 18:31:02 +0200, Thomas Kuehne <thomas-dloop kuehne.c=
n>  =

wrote:
 Please lift the current limitation and support all constructs allowed =

 StaticIfCondition in TemplateTypeParameterSpecialization too.

 Rewriting the B templates:
 #
 # template B( T : is(T =3D=3D class)) {
 #    /* ... */
 # }
 #
 # template B( T : is(T =3D=3D struct)) {
 #    /* ... */
 # }
 #

I fully agree.
Nov 12 2006