www.digitalmars.com         C & C++   DMDScript  

digitalmars.D - Forward declarations of template specilizations.

reply Ryan Bloomfield <_sir_maniacREMOVE_ME yahoo.com> writes:
I have an interesting issue, that makes me curious on how D handles it.

consider the following:
======================
module List;

template NodeTraits(NodeType)
{
	static NodeType getNext(NodeType v) { return v.next; }
}

class List(NodeType, Traits=NodeTraits!(NodeType))
{
	private NodeType head;

	
	NodeType next() { return Traits.getNext(head); }
}

======================
module main;

class Node {
	Node myNext;
}

template NodeTraits(NodeType : C)
{
	static NodeType getNext(NodeType v) { return v.myNext; }
}

main()
{
    	alias List!(Node) L;
	L l = new L();
	C next = l.next(); // error:  no property 'next' for type 'main.Node'
}
==============================================


  Templates are evaluated in the scope they are defined, which makes sense, but
when should the compiler check those definitions?  It makes sense that given 2
modules, one module shouldn't be able to change the behavior of another module,
having said that, c++ does allow this, and it proves very useful in customizing
the behavior of library classes.

  I noticed that if I change it to the following it works correctly(Traits
argument becomes an alias, and is passed in main):
======================
module List;

template NodeTraits(NodeType)
{
	static NodeType getNext(NodeType v) { return v.next; }
}

class List(NodeType, alias Traits)
{
	private NodeType head;

	
	NodeType next() { return Traits.getNext(head); }
}

======================
module main;

class Node {
	Node myNext;
}

template NodeTraits(NodeType : Node)
{
	static NodeType getNext(NodeType v) { return v.myNext; }
}

main()
{
       alias NodeTraits!(Node) Traits;  // a template's alias arguments only
take a single identifier
    	alias List!(Node, Traits) L;
	L l = new L();
	C next = l.next(); // Successfully accesses l.myNext
}
==============================================

Does the evaluation of a template have to know only the scope it was
instantiated in?  No forward declaration(of a module that imports it)?
Nov 14 2008
parent reply Christian Kamm <kamm-incasoftware removethis.de> writes:
 I have an interesting issue, that makes me curious on how D handles it.
 
 (Traits template code)

You cannot spread out template specializations across modules. If you define template Trait(T : S); in a.d and template Trait(T : C); in b.d and try to use alias Trait!(S) sinst; in use.d, you'll get Error: a.Trait(T : S) at a.d(3) conflicts with b.Trait(T : C) at b.d(3) because the two Traits live in separate scopes. This makes C++ style trait templates just not work in D. Does anyone know an equivalent?
Nov 16 2008
next sibling parent reply "Bill Baxter" <wbaxter gmail.com> writes:
On Sun, Nov 16, 2008 at 5:14 PM, Christian Kamm
<kamm-incasoftware removethis.de> wrote:
 I have an interesting issue, that makes me curious on how D handles it.

 (Traits template code)

You cannot spread out template specializations across modules. If you define template Trait(T : S); in a.d and template Trait(T : C); in b.d and try to use alias Trait!(S) sinst; in use.d, you'll get Error: a.Trait(T : S) at a.d(3) conflicts with b.Trait(T : C) at b.d(3) because the two Traits live in separate scopes. This makes C++ style trait templates just not work in D. Does anyone know an equivalent?

I think what Ryan said there is the general approach you have to take. Don't specialize the traits template, but rather pass in a whole new template as an alias parameter to the main template. This would be a good thing to add here: http://www.prowiki.org/wiki4d/wiki.cgi?PortingFromCxx Is there some canonical example of where you use specialized traits templates in C++? Or is this maybe a more general issue, like porting ADL code in C++. Not traits templates, but another ADL example is how you see IO done often in C++. With overloads for some common function like "write(Stream& o, ModuleSpecificType& val)". This pattern doesn't translate directly to D either. Suggestions? --bb
Nov 16 2008
parent reply Ryan Bloomfield <_sir_maniacREMOVE_ME yahoo.com> writes:
Bill Baxter Wrote:

 On Sun, Nov 16, 2008 at 5:14 PM, Christian Kamm
 <kamm-incasoftware removethis.de> wrote:
 I have an interesting issue, that makes me curious on how D handles it.

 (Traits template code)

You cannot spread out template specializations across modules. If you define template Trait(T : S); in a.d and template Trait(T : C); in b.d and try to use alias Trait!(S) sinst; in use.d, you'll get Error: a.Trait(T : S) at a.d(3) conflicts with b.Trait(T : C) at b.d(3) because the two Traits live in separate scopes. This makes C++ style trait templates just not work in D. Does anyone know an equivalent?

I think what Ryan said there is the general approach you have to take. Don't specialize the traits template, but rather pass in a whole new template as an alias parameter to the main template. This would be a good thing to add here: http://www.prowiki.org/wiki4d/wiki.cgi?PortingFromCxx Is there some canonical example of where you use specialized traits templates in C++? Or is this maybe a more general issue, like porting ADL code in C++. Not traits templates, but another ADL example is how you see IO done often in C++. With overloads for some common function like "write(Stream& o, ModuleSpecificType& val)". This pattern doesn't translate directly to D either. Suggestions? --bb

I think can understand why it works the way it does. ADL does sound a bit too complex(being hard to understand it's side-effect) to add to D. Polymorphism could be used as an alternative(the library class uses an interface to interact with the data), but that requires run-time overhead, but necessary anyway if polymorphism is involved in the data type. If I change the Traits from a template into a class template makes it easier to pass(no alias argument), the major difference is that the traits must be passed whenever it is overridden. According to http://www.digitalmars.com/d/1.0/templates-revisited.html(under "Template Parameters") a template can be passed as a template argument. How does one do that? The compiler (gdc) give an error when I try to pass a template like a type(complains it isn't a type). Ryan
Nov 16 2008
parent Frits van Bommel <fvbommel REMwOVExCAPSs.nl> writes:
Ryan Bloomfield wrote:
 According to http://www.digitalmars.com/d/1.0/templates-revisited.html(under
"Template Parameters") a template can be passed as a template argument.  How
does one do that? The compiler (gdc) give an error when I try to pass a
template like a type(complains it isn't a type).

Well, it's *not* a type, so that's understandable. It'll work as an alias parameter though.
Nov 16 2008
prev sibling next sibling parent "Jarrett Billingsley" <jarrett.billingsley gmail.com> writes:
On Sun, Nov 16, 2008 at 3:14 AM, Christian Kamm
<kamm-incasoftware removethis.de> wrote:
 I have an interesting issue, that makes me curious on how D handles it.

 (Traits template code)

You cannot spread out template specializations across modules. If you define template Trait(T : S); in a.d and template Trait(T : C); in b.d and try to use alias Trait!(S) sinst; in use.d, you'll get Error: a.Trait(T : S) at a.d(3) conflicts with b.Trait(T : C) at b.d(3) because the two Traits live in separate scopes. This makes C++ style trait templates just not work in D. Does anyone know an equivalent?

Do D2's overload sets solve this, or are those for functions only?
Nov 16 2008
prev sibling parent "Jarrett Billingsley" <jarrett.billingsley gmail.com> writes:
On Sun, Nov 16, 2008 at 3:52 PM, Ryan Bloomfield
<_sir_maniacREMOVE_ME yahoo.com> wrote:
 According to http://www.digitalmars.com/d/1.0/templates-revisited.html(under
"Template Parameters") a template can be passed as a template argument.  How
does one do that? The compiler (gdc) give an error when I try to pass a
template like a type(complains it isn't a type).

You use an alias parameter instead of a type parameter. template A(alias Foo) { alias Foo!(int) A; } template B(T) { T B; } alias A!(B) x; // same as declaring "int x"
Nov 16 2008