www.digitalmars.com         C & C++   DMDScript  

digitalmars.D - Question about explicit template instantiation

reply Edward Diener <eddielee_no_spam_here tropicsoft.com> writes:
I am working my way throught the pdf documentation ( 1.0 ) regarding 
templates in D and in the topic about explicit template instantiation 
and I came across the lines below, which have me stumped:

----------------------------------------------------------------

A template instantiation can be aliased:
template TFoo(T) { alias T* t; }
alias TFoo!(int) abc;
abc.t x; // declare x to be of type int*
Multiple instantiations of a TemplateDeclaration with the same 
TemplateArgumentList, before
implicit conversions, all will refer to the same instantiation. For example:
template TFoo(T) { T f; }
alias TFoo!(int) a;
alias TFoo!(int) b;
...

a.f = 3;
assert(b.f == 3); // a and b refer to the same instance of TFoo
This is true even if the TemplateInstances are done in different modules.

----------------------------------------------------------------

My confusion with the above is that an alias, when referring to a type, 
is the equivalent of a C++ typedef AFAICS. So 'a' and 'b' above are 
types ( because the instantiated template is a type ) and then I see the 
'a.f=3' line followed by the 'assert(b.f == 3)' line and I can not 
understand how a type can be used in either expression.

I am also assuming that the line beginning with "Multiple instantiations 
of a..." only mean that the 'a' and 'b' refer to the same type, but 
perhaps I have missed something in this explanation.
Feb 09 2008
next sibling parent reply "Tyro[a.c.edwards]" <no spam.com> writes:
Edward Diener さんは書きました:
 I am working my way throught the pdf documentation ( 1.0 ) regarding 
 templates in D and in the topic about explicit template instantiation 
 and I came across the lines below, which have me stumped:
 
 ----------------------------------------------------------------
 
 A template instantiation can be aliased:
 template TFoo(T) { alias T* t; }
 alias TFoo!(int) abc;
 abc.t x; // declare x to be of type int*
 Multiple instantiations of a TemplateDeclaration with the same 
 TemplateArgumentList, before
 implicit conversions, all will refer to the same instantiation. For 
 example:
 template TFoo(T) { T f; }
 alias TFoo!(int) a;
 alias TFoo!(int) b;
 ...
 
 a.f = 3;
 assert(b.f == 3); // a and b refer to the same instance of TFoo
 This is true even if the TemplateInstances are done in different modules.
 
 ----------------------------------------------------------------
 
 My confusion with the above is that an alias, when referring to a type, 
 is the equivalent of a C++ typedef AFAICS. So 'a' and 'b' above are 
 types ( because the instantiated template is a type ) and then I see the 
 'a.f=3' line followed by the 'assert(b.f == 3)' line and I can not 
 understand how a type can be used in either expression.
 
 I am also assuming that the line beginning with "Multiple instantiations 
 of a..." only mean that the 'a' and 'b' refer to the same type, but 
 perhaps I have missed something in this explanation.

The problem here is that you are misconstruing templates to be classes. Templates, like classes and other types, can be aliased, however since a template is not a type you couldn't use TFoo!(int) to declare a variable. This also applies to the derived aliases 'a' and 'b'. The templated class however, is a different story. Take the following code snipet for example: class Bar(T) { T f; } alias bar!(int) y; alias bar!(int) z; Here Bar(T) is a class, therefore Bar!(int) is a class instanciation: a type. Hence, the aliases, 'y' and 'z' are also types. Any attempts to use them as with the previous example, will result in an error. y.f = 3; // Error y is an instanciated class assert(z.f == 3); // Error y is an instanciated class Proper usage in this case is the same as any other class: y Y; // OK Y.f = 3; // Error memory not yet allocated for Y Y = new y; // OK Y.f = 3; // OK assert(Y.f == 3); //OK Hope that helps somewhat!
Feb 09 2008
next sibling parent reply Edward Diener <eddielee_no_spam_here tropicsoft.com> writes:
Tyro[a.c.edwards] wrote:
 Edward Diener さんは書きました:
 I am working my way throught the pdf documentation ( 1.0 ) regarding 
 templates in D and in the topic about explicit template instantiation 
 and I came across the lines below, which have me stumped:

 ----------------------------------------------------------------

 A template instantiation can be aliased:
 template TFoo(T) { alias T* t; }
 alias TFoo!(int) abc;
 abc.t x; // declare x to be of type int*
 Multiple instantiations of a TemplateDeclaration with the same 
 TemplateArgumentList, before
 implicit conversions, all will refer to the same instantiation. For 
 example:
 template TFoo(T) { T f; }
 alias TFoo!(int) a;
 alias TFoo!(int) b;
 ...

 a.f = 3;
 assert(b.f == 3); // a and b refer to the same instance of TFoo
 This is true even if the TemplateInstances are done in different modules.

 ----------------------------------------------------------------

 My confusion with the above is that an alias, when referring to a 
 type, is the equivalent of a C++ typedef AFAICS. So 'a' and 'b' above 
 are types ( because the instantiated template is a type ) and then I 
 see the 'a.f=3' line followed by the 'assert(b.f == 3)' line and I can 
 not understand how a type can be used in either expression.

 I am also assuming that the line beginning with "Multiple 
 instantiations of a..." only mean that the 'a' and 'b' refer to the 
 same type, but perhaps I have missed something in this explanation.

The problem here is that you are misconstruing templates to be classes. Templates, like classes and other types, can be aliased, however since a template is not a type you couldn't use TFoo!(int) to declare a variable. This also applies to the derived aliases 'a' and 'b'.

I understand what a template is and that the instantiation of a template is a type ( class ). So in the example above 'a' and 'b' are aliases for types, ie. typedef in C++. Therefore the statements "a.f = 3;" and 'assert(b.f == 3);" made no sense to me. But I think I understand them now, but hopefully someone will clarify things for me. It seems in D one can instantiate a temporary object from a type which has a default constructor simply by using the type, whereas in C++ one must use the type followed by '()'. So whereas if X were a class with a default constructor with the data member Y, in C++ one would use 'X().Y' to access the temporary's Y data member while in D it appears one can use 'X.Y' to access the temporary's data member. The previous explanation is the only way I can make sense of the two statements above which led to my OP.
 
 The templated class however, is a different story. Take the following 
 code snipet for example:
 
     class Bar(T)
     {
         T f;
     }
 
     alias bar!(int) y;
     alias bar!(int) z;
 
 Here Bar(T) is a class, therefore Bar!(int) is a class instanciation: a 
 type. Hence, the aliases, 'y' and 'z' are also types. Any attempts to 
 use them as with the previous example, will result in an error.
 
     y.f = 3; // Error y is an instanciated class
     assert(z.f == 3); // Error y is an instanciated class

What I quoted in my OP was all directly from the documentation, not anything I made up. Somehow you think that the lines: a.f = 3; assert(b.f == 3); // a and b refer to the same instance of TFoo were inserted by me. No ! They were in the doc and they appeared to be incorrect, and I wanted an explanation for them.
Feb 10 2008
next sibling parent reply Edward Diener <eddielee_no_spam_here tropicsoft.com> writes:
Janice Caron wrote:
 On 10/02/2008, Edward Diener <eddielee_no_spam_here tropicsoft.com> wrote:
 But I think I understand them now, but hopefully someone will clarify
 things for me. It seems in D one can instantiate a temporary object from
 a type which has a default constructor simply by using the type, whereas
 in C++ one must use the type followed by '()'. So whereas if X were a
 class with a default constructor with the data member Y, in C++ one
 would use 'X().Y' to access the temporary's Y data member while in D it
 appears one can use 'X.Y' to access the temporary's data member.

Alas no. You can omit the brackets, but you cannot omit the word "new". Thus, it would be either new X().Y or (new X).Y

Understood. I forgot all non-struct classes must be in GC memory.
 
 A template is not necessarily a class. You can have template classes,
 but not all templates are classes. You can also have template
 functions, but not all templates are functions. The most general
 statement would probably be that a template is a namespace. Thus:
 
     template MyNamespace(T)
     {
         int x;
     }

A template being a namespace in D is certainly different from C++.
 
 generates a different namespace for each different type of T. So in
 the above example, x is a global variable, not a member variable,
 within MyNamespace!(T) for some T. Therefore:
 
     MyNamesspace!(int).x
 
 is a different variable from
 
     MyNamespace!(double).x
 
 because the Ts are different. If I choose to save typing by writing:
 
     alias MyNamespace!(int) A;
     alias MyNamespace!(double) B;
 
 then A.x and B.x would still be different global variables. However,
 if I later write
 
     alias MyNamespace!(int) C;
 
 then C refers to the /same/ namespace as A, and hence A.x and C.x are
 the exact same global variable.

This is confusing to me coming from C++. In C++ instantiating a class template produces a type. Is that not the way D works ? If not, what does instantiating a template produce in D and, if it does not produce a type, how does one instantiate a template which does produce a type in D ?
Feb 10 2008
parent reply Edward Diener <eddielee_no_spam_here tropicsoft.com> writes:
Janice Caron wrote:
 On 10/02/2008, Edward Diener <eddielee_no_spam_here tropicsoft.com> wrote:
     template MyNamespace(T)
     {
         int x;
     }


 This is confusing to me coming from C++. In C++ instantiating a class
 template produces a type. Is that not the way D works ?

That's /exactly/ the way that D works. With CLASS templates, D works just like C++. No problem. Compare: c++ template<class T> class A { int x; }; A<int> a1; A<double> a2; and the D equivalent: class A(T) { int x; } auto a1 = new A!(int); auto a2 = new A!(double); They're exactly the same, except that D has nicer syntax. I don't think /class/ templates are confusing you at all! I think what's confusing you is that in D you can have /namespace/ templates, which don't exist in C++.

The explanation for Class Templates in the D1 doc does not explain anything at all. That is why I assumed the template A(T) notation referred to the equivalent of the C++ class template.
 
 Let me make an approximate C++ translation. Here's the D again:
 
     template A(T)
     {
         int x;
     }
 
 That is roughly equivalent to, in C++
 
     namespace A_int
     {
         int x;
     }
 
     namespace A_float
     {
         int x;
     }
 
     namespace A_double
     {
         int x;
     }
 
 ...and so on for every imaginable type. Now it should be clear to you
 that A_int::x is a different variable from A_float::x, yes?

Now I understand. I was surely fooled by the doc.
 
 For a namespaces to be "instantiated" just means that the
 corresponding chunk of code is there. To be /not/ instantiated would
 mean that it isn't there - which is just as well really, because there
 are in infinite number of possible types!
 
 To instantiate a namespace template, you only have to refer to it. I
 doesn't matter how.
 
 Clear?

I think so. Instantiating a namespace template merely puts the equivalent code, with the types you instantiate it with substituted each time those types are referred to in the namespace, directly into your source. I still do not understand what the object used for the instantiation is. In your example above what is: A!(int) ? Is it some kind of namespace ? Can I say: A!(int) x; ? If so, what is x ?
Feb 10 2008
parent Edward Diener <eddielee_no_spam_here tropicsoft.com> writes:
Janice Caron wrote:
 On 10/02/2008, Edward Diener <eddielee_no_spam_here tropicsoft.com> wrote:
 I still do not understand what the object used for the instantiation is.
 In your example above what is:

 A!(int)

 ? Is it some kind of namespace ?

Yes. It is exactly a namespace.
 Can I say:

 A!(int) x;

 ?

Sometimes, but only in special case. If you don't specify a member of the namespace, then the compiler will /assume/ a member whose name is the same as that of the template. So, if we have: template A(T) { int A; } then A!(int) x; would be shorthand for A!(int).A x; But if there wasn't an A in the namespace, then it wouldn't compile. That little "trick" is really, really useful, because it can make for a lot less typing. So - in general - A!(T) with no member, is the same thing as A!(T).A, if A!(T).A exists. /What/ is it, depends. It's whatever A!(T).A is.

Thanks for the explanation !
Feb 11 2008
prev sibling parent "Tyro[a.c.edwards]" <no spam.com> writes:
Edward Diener さんは書きました:
 Tyro[a.c.edwards] wrote:
 Edward Diener さんは書きました:


[snip]
 
 I understand what a template is and that the instantiation of a template 
 is a type ( class ). So in the example above 'a' and 'b' are aliases for 
 types, ie. typedef in C++. Therefore the statements "a.f = 3;" and 
 'assert(b.f == 3);" made no sense to me.

Actually, I said a "template is NOT a type." However, I don't tink I have enought experience in either English or D to explain thing to you so I'll stop before embarrasing myself further.
 But I think I understand them now, but hopefully someone will clarify 
 things for me. It seems in D one can instantiate a temporary object from 
 a type which has a default constructor simply by using the type, whereas 
 in C++ one must use the type followed by '()'. So whereas if X were a 
 class with a default constructor with the data member Y, in C++ one 
 would use 'X().Y' to access the temporary's Y data member while in D it 
 appears one can use 'X.Y' to access the temporary's data member.

Unfortunately I don't think you undersand... see previous comment.
 What I quoted in my OP was all directly from the documentation, not 
 anything I made up. Somehow you think that the lines:
 
 a.f = 3;
 assert(b.f == 3); // a and b refer to the same instance of TFoo
 
 were inserted by me. No ! They were in the doc and they appeared to be 
 incorrect, and I wanted an explanation for them.

No, actually I went to the document that you were reading, read a little further down the page and took an example of a CLASS template and used it to attempt an explanation. Hopefully, someone will be able to assist you. Good luck! Andrew
Feb 10 2008
prev sibling next sibling parent "Janice Caron" <caron800 googlemail.com> writes:
On 10/02/2008, Edward Diener <eddielee_no_spam_here tropicsoft.com> wrote:
 But I think I understand them now, but hopefully someone will clarify
 things for me. It seems in D one can instantiate a temporary object from
 a type which has a default constructor simply by using the type, whereas
 in C++ one must use the type followed by '()'. So whereas if X were a
 class with a default constructor with the data member Y, in C++ one
 would use 'X().Y' to access the temporary's Y data member while in D it
 appears one can use 'X.Y' to access the temporary's data member.

Alas no. You can omit the brackets, but you cannot omit the word "new". Thus, it would be either new X().Y or (new X).Y A template is not necessarily a class. You can have template classes, but not all templates are classes. You can also have template functions, but not all templates are functions. The most general statement would probably be that a template is a namespace. Thus: template MyNamespace(T) { int x; } generates a different namespace for each different type of T. So in the above example, x is a global variable, not a member variable, within MyNamespace!(T) for some T. Therefore: MyNamesspace!(int).x is a different variable from MyNamespace!(double).x because the Ts are different. If I choose to save typing by writing: alias MyNamespace!(int) A; alias MyNamespace!(double) B; then A.x and B.x would still be different global variables. However, if I later write alias MyNamespace!(int) C; then C refers to the /same/ namespace as A, and hence A.x and C.x are the exact same global variable.
Feb 10 2008
prev sibling next sibling parent "Janice Caron" <caron800 googlemail.com> writes:
On 10/02/2008, Edward Diener <eddielee_no_spam_here tropicsoft.com> wrote:
     template MyNamespace(T)
     {
         int x;
     }


 This is confusing to me coming from C++. In C++ instantiating a class
 template produces a type. Is that not the way D works ?

That's /exactly/ the way that D works. With CLASS templates, D works just like C++. No problem. Compare: c++ template<class T> class A { int x; }; A<int> a1; A<double> a2; and the D equivalent: class A(T) { int x; } auto a1 = new A!(int); auto a2 = new A!(double); They're exactly the same, except that D has nicer syntax. I don't think /class/ templates are confusing you at all! I think what's confusing you is that in D you can have /namespace/ templates, which don't exist in C++. Let me make an approximate C++ translation. Here's the D again: template A(T) { int x; } That is roughly equivalent to, in C++ namespace A_int { int x; } namespace A_float { int x; } namespace A_double { int x; } ...and so on for every imaginable type. Now it should be clear to you that A_int::x is a different variable from A_float::x, yes? For a namespaces to be "instantiated" just means that the corresponding chunk of code is there. To be /not/ instantiated would mean that it isn't there - which is just as well really, because there are in infinite number of possible types! To instantiate a namespace template, you only have to refer to it. I doesn't matter how. Clear?
Feb 10 2008
prev sibling next sibling parent Jesse Phillips <jessekphillips gmail.com> writes:
On Sun, 10 Feb 2008 17:31:36 -0500, Edward Diener wrote:

 Janice Caron wrote:
 On 10/02/2008, Edward Diener <eddielee_no_spam_here tropicsoft.com>
 wrote:
     template MyNamespace(T)
     {
         int x;
     }


 This is confusing to me coming from C++. In C++ instantiating a class
 template produces a type. Is that not the way D works ?

That's /exactly/ the way that D works. With CLASS templates, D works just like C++. No problem. Compare: c++ template<class T> class A { int x; }; A<int> a1; A<double> a2; and the D equivalent: class A(T) { int x; } auto a1 = new A!(int); auto a2 = new A!(double); They're exactly the same, except that D has nicer syntax. I don't think /class/ templates are confusing you at all! I think what's confusing you is that in D you can have /namespace/ templates, which don't exist in C++.

The explanation for Class Templates in the D1 doc does not explain anything at all. That is why I assumed the template A(T) notation referred to the equivalent of the C++ class template.
 Let me make an approximate C++ translation. Here's the D again:
 
     template A(T)
     {
         int x;
     }
 
 That is roughly equivalent to, in C++
 
     namespace A_int
     {
         int x;
     }
 
     namespace A_float
     {
         int x;
     }
 
     namespace A_double
     {
         int x;
     }
 
 ...and so on for every imaginable type. Now it should be clear to you
 that A_int::x is a different variable from A_float::x, yes?

Now I understand. I was surely fooled by the doc.
 For a namespaces to be "instantiated" just means that the corresponding
 chunk of code is there. To be /not/ instantiated would mean that it
 isn't there - which is just as well really, because there are in
 infinite number of possible types!
 
 To instantiate a namespace template, you only have to refer to it. I
 doesn't matter how.
 
 Clear?

I think so. Instantiating a namespace template merely puts the equivalent code, with the types you instantiate it with substituted each time those types are referred to in the namespace, directly into your source. I still do not understand what the object used for the instantiation is. In your example above what is: A!(int) ? Is it some kind of namespace ? Can I say: A!(int) x; ? If so, what is x ?

Well, you can't write A!(int) x; unless you precede it with alias. If we have: template A(T) { T f; } I'm new to templates so I don't really know how to say what A!(int) is, but I think a good way to think of it as declaring an instance of a struct. struct B { int f }; where B = A!(int);
Feb 10 2008
prev sibling next sibling parent Jesse Phillips <jessekphillips gmail.com> writes:
On Sun, 10 Feb 2008 22:58:51 +0000, Jesse Phillips wrote:

 On Sun, 10 Feb 2008 17:31:36 -0500, Edward Diener wrote:
 
 Janice Caron wrote:
 On 10/02/2008, Edward Diener <eddielee_no_spam_here tropicsoft.com>
 wrote:
     template MyNamespace(T)
     {
         int x;
     }


 This is confusing to me coming from C++. In C++ instantiating a class
 template produces a type. Is that not the way D works ?

That's /exactly/ the way that D works. With CLASS templates, D works just like C++. No problem. Compare: c++ template<class T> class A { int x; }; A<int> a1; A<double> a2; and the D equivalent: class A(T) { int x; } auto a1 = new A!(int); auto a2 = new A!(double); They're exactly the same, except that D has nicer syntax. I don't think /class/ templates are confusing you at all! I think what's confusing you is that in D you can have /namespace/ templates, which don't exist in C++.

The explanation for Class Templates in the D1 doc does not explain anything at all. That is why I assumed the template A(T) notation referred to the equivalent of the C++ class template.
 Let me make an approximate C++ translation. Here's the D again:
 
     template A(T)
     {
         int x;
     }
 
 That is roughly equivalent to, in C++
 
     namespace A_int
     {
         int x;
     }
 
     namespace A_float
     {
         int x;
     }
 
     namespace A_double
     {
         int x;
     }
 
 ...and so on for every imaginable type. Now it should be clear to you
 that A_int::x is a different variable from A_float::x, yes?

Now I understand. I was surely fooled by the doc.
 For a namespaces to be "instantiated" just means that the
 corresponding chunk of code is there. To be /not/ instantiated would
 mean that it isn't there - which is just as well really, because there
 are in infinite number of possible types!
 
 To instantiate a namespace template, you only have to refer to it. I
 doesn't matter how.
 
 Clear?

I think so. Instantiating a namespace template merely puts the equivalent code, with the types you instantiate it with substituted each time those types are referred to in the namespace, directly into your source. I still do not understand what the object used for the instantiation is. In your example above what is: A!(int) ? Is it some kind of namespace ? Can I say: A!(int) x; ? If so, what is x ?

Well, you can't write A!(int) x; unless you precede it with alias. If we have: template A(T) { T f; } I'm new to templates so I don't really know how to say what A!(int) is, but I think a good way to think of it as declaring an instance of a struct. struct B { int f }; where B = A!(int);

Hold on I just made a type out of A!(int) so A!(int) would be equivalent to struct B { int f }; B a; where B a is A!(int);
Feb 10 2008
prev sibling next sibling parent "Janice Caron" <caron800 googlemail.com> writes:
On 10/02/2008, Edward Diener <eddielee_no_spam_here tropicsoft.com> wrote:
 I still do not understand what the object used for the instantiation is.
 In your example above what is:

 A!(int)

 ? Is it some kind of namespace ?

Yes. It is exactly a namespace.
 Can I say:

 A!(int) x;

 ?

Sometimes, but only in special case. If you don't specify a member of the namespace, then the compiler will /assume/ a member whose name is the same as that of the template. So, if we have: template A(T) { int A; } then A!(int) x; would be shorthand for A!(int).A x; But if there wasn't an A in the namespace, then it wouldn't compile. That little "trick" is really, really useful, because it can make for a lot less typing. So - in general - A!(T) with no member, is the same thing as A!(T).A, if A!(T).A exists. /What/ is it, depends. It's whatever A!(T).A is.
Feb 10 2008
prev sibling next sibling parent "Janice Caron" <caron800 googlemail.com> writes:
On 10/02/2008, Jesse Phillips <jessekphillips gmail.com> wrote:
 Well, you can't write A!(int) x; unless you precede it with alias.

Not so. template A(T) { int A; } A!(double) = 42; writefln(A!(double)); // prints 42 writefln(typeof(A!(double))); // prints double In this example, A!(double) is short for A!(double).A, which in an int, so we can assign a value to it and print it. But template A(T) { struct A { int x; } } In /this/ example A!(T).A is a type. (And hence, so is A!(T)). Observe that there's a neater way of writing that though. We can abbreviate that to struct A(T) { int x; }
Feb 10 2008
prev sibling parent "Janice Caron" <caron800 googlemail.com> writes:
On 10/02/2008, Janice Caron <caron800 googlemail.com> wrote:
 On 10/02/2008, Jesse Phillips <jessekphillips gmail.com> wrote:
 Well, you can't write A!(int) x; unless you precede it with alias.

Not so. template A(T) { int A; } A!(double) = 42; writefln(A!(double)); // prints 42 writefln(typeof(A!(double))); // prints double

Whoa! Big mistake! Sorry. Typo. Got that wrong. Don't want to confuse anyone! Let's try again... writefln(typeof(A!(double))); // prints int That's better! Phew!
Feb 10 2008
prev sibling parent reply "Jarrett Billingsley" <kb3ctd2 yahoo.com> writes:
"Edward Diener" <eddielee_no_spam_here tropicsoft.com> wrote in message 
news:foleie$67q$1 digitalmars.com...
I am working my way throught the pdf documentation ( 1.0 ) regarding 
templates in D and in the topic about explicit template instantiation and I 
came across the lines below, which have me stumped:

 ----------------------------------------------------------------

 A template instantiation can be aliased:
 template TFoo(T) { alias T* t; }
 alias TFoo!(int) abc;
 abc.t x; // declare x to be of type int*
 Multiple instantiations of a TemplateDeclaration with the same 
 TemplateArgumentList, before
 implicit conversions, all will refer to the same instantiation. For 
 example:
 template TFoo(T) { T f; }
 alias TFoo!(int) a;
 alias TFoo!(int) b;
 ...

 a.f = 3;
 assert(b.f == 3); // a and b refer to the same instance of TFoo
 This is true even if the TemplateInstances are done in different modules.

 ----------------------------------------------------------------

 My confusion with the above is that an alias, when referring to a type, is 
 the equivalent of a C++ typedef AFAICS. So 'a' and 'b' above are types ( 
 because the instantiated template is a type ) and then I see the 'a.f=3' 
 line followed by the 'assert(b.f == 3)' line and I can not understand how 
 a type can be used in either expression.

Aliases are a superset of the C/C++ typedef. An alias is much more general, allowing you to not only rename types, but more generally, create a new symbol (name) that refers to another symbol. This way, you can alias types, template instantiations, functions, methods, modules, etc. etc. What's happening here is that TFoo is not a type, and an instance of TFoo is not a type either. TFoo, when instantiated, is more like a namespace. It has a single variable, f. This is not a field or anything, it's just a variable. When you instantiate TFoo with a type, you basically declare a global variable TFoo!(T).f. So: template TFoo(T) { T f; } void foo() { alias TFoo!(int) a; a.f++; Stdout.formatln("{}", a.f); } void main() { foo(); foo(); } prints 1 and 2. Notice that even though 'a' was aliased inside foo(), it's kind of like a static variable. Contrast this with mixins, where the declarations are inserted at the instantiation location: void foo() { mixin TFoo!(int) a; a.f++; Stdout.formatln("{}", a.f); } This prints 1 and 1, since a.f is now basically a local variable.
 I am also assuming that the line beginning with "Multiple instantiations 
 of a..." only mean that the 'a' and 'b' refer to the same type, but 
 perhaps I have missed something in this explanation.

a and b refer to the same *symbol*, yes. But instantiations of TFoo are not types.
Feb 10 2008
parent reply Edward Diener <eddielee_no_spam_here tropicsoft.com> writes:
Jarrett Billingsley wrote:
 "Edward Diener" <eddielee_no_spam_here tropicsoft.com> wrote in message 
 news:foleie$67q$1 digitalmars.com...
 I am working my way throught the pdf documentation ( 1.0 ) regarding 
 templates in D and in the topic about explicit template instantiation and I 
 came across the lines below, which have me stumped:

 ----------------------------------------------------------------

 A template instantiation can be aliased:
 template TFoo(T) { alias T* t; }
 alias TFoo!(int) abc;
 abc.t x; // declare x to be of type int*
 Multiple instantiations of a TemplateDeclaration with the same 
 TemplateArgumentList, before
 implicit conversions, all will refer to the same instantiation. For 
 example:
 template TFoo(T) { T f; }
 alias TFoo!(int) a;
 alias TFoo!(int) b;
 ...

 a.f = 3;
 assert(b.f == 3); // a and b refer to the same instance of TFoo
 This is true even if the TemplateInstances are done in different modules.

 ----------------------------------------------------------------

 My confusion with the above is that an alias, when referring to a type, is 
 the equivalent of a C++ typedef AFAICS. So 'a' and 'b' above are types ( 
 because the instantiated template is a type ) and then I see the 'a.f=3' 
 line followed by the 'assert(b.f == 3)' line and I can not understand how 
 a type can be used in either expression.

Aliases are a superset of the C/C++ typedef. An alias is much more general, allowing you to not only rename types, but more generally, create a new symbol (name) that refers to another symbol. This way, you can alias types, template instantiations, functions, methods, modules, etc. etc.

Understood.
 
 What's happening here is that TFoo is not a type, and an instance of TFoo is 
 not a type either.
  TFoo, when instantiated, is more like a namespace.  It 
 has a single variable, f.  This is not a field or anything, it's just a 
 variable.  When you instantiate TFoo with a type, you basically declare a 
 global variable TFoo!(T).f.  So:
 
 template TFoo(T)
 {
     T f;
 }
 
 void foo()
 {
     alias TFoo!(int) a;
     a.f++;
     Stdout.formatln("{}", a.f);
 }
 
 void main()
 {
     foo();
     foo();
 }
 
 prints 1 and 2.  Notice that even though 'a' was aliased inside foo(), it's 
 kind of like a static variable.

This is utterly confusing to me coming from C++. Instantiating templates in C++ produce a type. If a template instantiation is not a type, what is it ? Also how does one produce a type from a template in D ?
 
 Contrast this with mixins, where the declarations are inserted at the 
 instantiation location:
 
 void foo()
 {
     mixin TFoo!(int) a;
     a.f++;
     Stdout.formatln("{}", a.f);
 }
 
 This prints 1 and 1, since a.f is now basically a local variable.

I will tackle mixins once I understand D templates, but I am now lost.
 
 I am also assuming that the line beginning with "Multiple instantiations 
 of a..." only mean that the 'a' and 'b' refer to the same type, but 
 perhaps I have missed something in this explanation.

a and b refer to the same *symbol*, yes. But instantiations of TFoo are not types.

Thanks for the information but I await your and Janice's response about what a template instantiation is. I admit I am lost now with D templates and the doc sure did not prepare me for whatever a template instantiation is supposed to be.
Feb 10 2008
next sibling parent bearophile <bearophileHUGS lycos.com> writes:
Edward Diener:
 Thanks for the information but I await your and Janice's response about 
 what a template instantiation is.

The situation is rather simple. A D template is a section of code that is parametric in one or more types. Just like a function is a piece of code that is parametric on the value of some types (the situation isn't fully symmetric because in D types aren't first class values yet, but they are close enough for many purposes). Inside that section you can put what you want, types that depend of the template types, classes that are depends of the template types (that you can think as variables), etc. When you instantiate a type you give the value to those type variables, so you just define what types those "type variables" are, so you define real pieces of code, for functions, classes, etc, that you can take a pointer of, you can instantiate, you can call, etc. Before that, they are "virtual", generic, not even fully cheeked by the compiler. As time passes, D types become a bit more and more first class, that allows you to operate on them in more ways (at compile time). Bye, bearophile
Feb 10 2008
prev sibling parent reply "Jarrett Billingsley" <kb3ctd2 yahoo.com> writes:
"Edward Diener" <eddielee_no_spam_here tropicsoft.com> wrote in message 
news:fonlr1$2krb$1 digitalmars.com...

 This is utterly confusing to me coming from C++. Instantiating templates 
 in C++ produce a type. If a template instantiation is not a type, what is 
 it ? Also how does one produce a type from a template in D ?

As Janice said, instantiating a template creates a namespace in which the template parameters are replaced by the arguments given in the instantiation. C++'s templates are intrinsically bound to either classes or functions, and instantiating a template in C++ gets you either a class or a function. D's templates are more general; they simply declare a namespace in which one or more declarations can exist, all parameterized by the template's parameters. It might help to know that this: class A(T) { .. } is _exactly_ equivalent (and in fact turned into this by the compiler) to: template A(T) { class A { ... } } Why this works is because if a template contains exactly one declaration, and that declaration has the same name as the template, referring to the template instantiation refers to the symbol inside it. So: A!(int).A a; A!(int) b; // sugar for the previous line Function templates work similarly. void foo(T)() { ... } == template foo(T) { void foo() { } } So this function can be called either as foo!(int)() or as foo!(int).foo(). This extends to any kind of declaration. template A(T, U) { T t; U u; } template A(T) { // an alias is a declaration too. alias A!(T, T) A; } alias A!(int, float) one; // one.t is int, one.u is float // we don't have to say A!(char).A alias A!(char) two; // both two.t and two.u are char You can have more than one declaration in a template, but then the "automatic symbol use" magic stops happening.
Feb 10 2008
parent Edward Diener <eddielee_no_spam_here tropicsoft.com> writes:
Jarrett Billingsley wrote:
 "Edward Diener" <eddielee_no_spam_here tropicsoft.com> wrote in message 
 news:fonlr1$2krb$1 digitalmars.com...
 
 This is utterly confusing to me coming from C++. Instantiating templates 
 in C++ produce a type. If a template instantiation is not a type, what is 
 it ? Also how does one produce a type from a template in D ?

As Janice said, instantiating a template creates a namespace in which the template parameters are replaced by the arguments given in the instantiation. C++'s templates are intrinsically bound to either classes or functions, and instantiating a template in C++ gets you either a class or a function. D's templates are more general; they simply declare a namespace in which one or more declarations can exist, all parameterized by the template's parameters. It might help to know that this: class A(T) { .. } is _exactly_ equivalent (and in fact turned into this by the compiler) to: template A(T) { class A { ... } } Why this works is because if a template contains exactly one declaration, and that declaration has the same name as the template, referring to the template instantiation refers to the symbol inside it. So: A!(int).A a; A!(int) b; // sugar for the previous line Function templates work similarly. void foo(T)() { ... } == template foo(T) { void foo() { } } So this function can be called either as foo!(int)() or as foo!(int).foo(). This extends to any kind of declaration. template A(T, U) { T t; U u; } template A(T) { // an alias is a declaration too. alias A!(T, T) A; } alias A!(int, float) one; // one.t is int, one.u is float // we don't have to say A!(char).A alias A!(char) two; // both two.t and two.u are char You can have more than one declaration in a template, but then the "automatic symbol use" magic stops happening.

Thanks for the explanation !
Feb 11 2008