www.digitalmars.com         C & C++   DMDScript  

digitalmars.D - Q: What are the rules for emitting template code?

reply Austin Hastings <ah08010-d yahoo.com> writes:
Howdy,

This is a bit involved, so bear with me.

Suppose I have a template, Decider(Args...) and some other templates, 
Option1(...), Option2(...), etc.

The job of Decider() is to decide, based on the given parameters, which 
of the possible OptionN templates to use.

Decider uses "static if" and some builtins and maybe some CTFE to 
determine its result.

Now:

How much can Decider ask of one of the Option templates without that 
template being expensively realized?

Alternatively:

What parts of an Option template have to be realized for Decider to do 
its job?

In particular:

If Decider uses Option1.sizeof, does any Option1 code get emitted?

If Decider uses some external function that makes use of type aliases in 
Option1, (example:  Option1() { alias byte value_t; } ) does any Option1 
code get emitted?

If Decider uses some function defined inside the same module with 
Option1, but NOT inside of Option1, does any/all of the Option1 code get 
emitted?

If Decider uses a static method of Option1, does any more of the Option1 
code get emitted?



Obviously, I am trying to ... decide ... how to do compile time 
selection. But I'm also just a tad curious at the internals of the 
template engine.

Thanks,

=Austin
Oct 23 2010
next sibling parent reply "Simen kjaeraas" <simen.kjaras gmail.com> writes:
Austin Hastings <ah08010-d yahoo.com> wrote:

 If Decider uses Option1.sizeof, does any Option1 code get emitted?
For sizeof to be known, the template would have to be instantiated, yes.
 If Decider uses some external function that makes use of type aliases in  
 Option1, (example:  Option1() { alias byte value_t; } ) does any Option1  
 code get emitted?
Again, the same.
 If Decider uses some function defined inside the same module with  
 Option1, but NOT inside of Option1, does any/all of the Option1 code get  
 emitted?
Accessing the surrounding scope would not instantiate Option1. So no.
 If Decider uses a static method of Option1, does any more of the Option1  
 code get emitted?
As with the first two, it would have to be instantiated. Now, I have the feeling this is not really what you're asking for. What do you mean by 'code gets emitted'? Perhaps you could give a reduced example? -- Simen
Oct 24 2010
parent reply Austin Hastings <ah08010-d yahoo.com> writes:
On 10/24/2010 5:16 AM, Simen kjaeraas wrote:
 Austin Hastings <ah08010-d yahoo.com> wrote:

 If Decider uses Option1.sizeof, does any Option1 code get emitted?
For sizeof to be known, the template would have to be instantiated, yes.
Instantiated does not necessarily imply emitting code, I think. (Of course, this is why I asked - to find out the compiler behavior and expectations.)
 If Decider uses a static method of Option1, does any more of the
 Option1 code get emitted?
As with the first two, it would have to be instantiated. Now, I have the feeling this is not really what you're asking for. What do you mean by 'code gets emitted'? Perhaps you could give a reduced example?
What I am trying to do is to pass a set of expected behavior to a template. The template would make a decision based on memory versus performance as to which of several possible implementations to use. For example, a list might be implemented as a dynamic array, or as a linked list (or ... or... or...). If I asked for a list with single-ended insert/remove, then a dynamic array is going to win on overhead. If I ask for insert-in-the-middle, then the linked list would win on performance. Ideally, each of the option templates would somehow provide a set of metrics so I can ask "hey, for 100 elements, what are your memory/performance metrics?" Which leads to wondering how much of the metric has to be outside the option template to avoid inadvertently generating extra object code that won't get used. =Austin
Oct 25 2010
parent Jonathan M Davis <jmdavisProg gmx.com> writes:
On Monday, October 25, 2010 06:08:24 Austin Hastings wrote:
 On 10/24/2010 5:16 AM, Simen kjaeraas wrote:
 Austin Hastings <ah08010-d yahoo.com> wrote:
 If Decider uses Option1.sizeof, does any Option1 code get emitted?
For sizeof to be known, the template would have to be instantiated, yes.
Instantiated does not necessarily imply emitting code, I think. (Of course, this is why I asked - to find out the compiler behavior and expectations.)
They're exactly the same thing. When a template is instantiated, a copy of that template is created with the paramaters that it was given. The only reason new code wouldn't be emitted would be is if that particular set of parameters had already been used with that template and so there was no need to create it anew. - Jonathan M Davis
Oct 25 2010
prev sibling parent reply "Steven Schveighoffer" <schveiguy yahoo.com> writes:
On Sun, 24 Oct 2010 00:06:23 -0400, Austin Hastings <ah08010-d yahoo.com>  
wrote:

 Howdy,

 This is a bit involved, so bear with me.

 Suppose I have a template, Decider(Args...) and some other templates,  
 Option1(...), Option2(...), etc.

 The job of Decider() is to decide, based on the given parameters, which  
 of the possible OptionN templates to use.

 Decider uses "static if" and some builtins and maybe some CTFE to  
 determine its result.

 Now:

 How much can Decider ask of one of the Option templates without that  
 template being expensively realized?

 Alternatively:

 What parts of an Option template have to be realized for Decider to do  
 its job?

 In particular:

 If Decider uses Option1.sizeof, does any Option1 code get emitted?

 If Decider uses some external function that makes use of type aliases in  
 Option1, (example:  Option1() { alias byte value_t; } ) does any Option1  
 code get emitted?

 If Decider uses some function defined inside the same module with  
 Option1, but NOT inside of Option1, does any/all of the Option1 code get  
 emitted?

 If Decider uses a static method of Option1, does any more of the Option1  
 code get emitted?



 Obviously, I am trying to ... decide ... how to do compile time  
 selection. But I'm also just a tad curious at the internals of the  
 template engine.
One of the major problems with the template system IMO is compile-time templates (that is, templates that are only used at compile time) are emitted into the executable, even though they are not used. Take for example, isForwardRange(R). A function like this: void foo(R) if (isForwardRange!R) is going to instantiate isForwardRange!R, which may instantiate other templates to check to see if isForwardRange is true. But all these things end up in the executable, even though they aren't used. Now, if you are concerned about executable footprint, this problem I think will eventually be solved (not sure if there is a bug report, but I think I've brought it up before, and the consensus is that it should not end up in the exe). If you are concerned that the runtime of the *compiler* might be too long, then I'm afraid you are just going to have to deal with it. Everything in a compiled language is focused first on the resulting executable. It's perfectly normal for a compiler to take extra time compiling to make the executable more efficient. -Steve
Oct 25 2010
parent Fawzi Mohamed <fawzi gmx.ch> writes:
On 25-ott-10, at 18:04, Steven Schveighoffer wrote:

 On Sun, 24 Oct 2010 00:06:23 -0400, Austin Hastings <ah08010-d yahoo.com 
 wrote:
 Howdy,

 This is a bit involved, so bear with me.

 Suppose I have a template, Decider(Args...) and some other  
 templates, Option1(...), Option2(...), etc.

 The job of Decider() is to decide, based on the given parameters,  
 which of the possible OptionN templates to use.

 Decider uses "static if" and some builtins and maybe some CTFE to  
 determine its result.

 Now:

 How much can Decider ask of one of the Option templates without  
 that template being expensively realized?

 Alternatively:

 What parts of an Option template have to be realized for Decider to  
 do its job?

 In particular:

 If Decider uses Option1.sizeof, does any Option1 code get emitted?

 If Decider uses some external function that makes use of type  
 aliases in Option1, (example:  Option1() { alias byte value_t; } )  
 does any Option1 code get emitted?

 If Decider uses some function defined inside the same module with  
 Option1, but NOT inside of Option1, does any/all of the Option1  
 code get emitted?

 If Decider uses a static method of Option1, does any more of the  
 Option1 code get emitted?



 Obviously, I am trying to ... decide ... how to do compile time  
 selection. But I'm also just a tad curious at the internals of the  
 template engine.
One of the major problems with the template system IMO is compile- time templates (that is, templates that are only used at compile time) are emitted into the executable, even though they are not used. Take for example, isForwardRange(R). A function like this: void foo(R) if (isForwardRange!R) is going to instantiate isForwardRange!R, which may instantiate other templates to check to see if isForwardRange is true. But all these things end up in the executable, even though they aren't used. Now, if you are concerned about executable footprint, this problem I think will eventually be solved (not sure if there is a bug report, but I think I've brought it up before, and the consensus is that it should not end up in the exe). If you are concerned that the runtime of the *compiler* might be too long, then I'm afraid you are just going to have to deal with it. Everything in a compiled language is focused first on the resulting executable. It's perfectly normal for a compiler to take extra time compiling to make the executable more efficient. -Steve
I find that having no clear rule to where a template is emitted when compiling several files at once is a larger problem. I would much prefer to have something that follows some rules like: sort imports: if a includes b and b does not include a: a>b if a includes b and b does include a: order a,b using lexicographic ordering of their module name if b includes a (and a does not include b): b>a else neutral when emitting a don't emit any template that was instantiated by modules included that come before a, and *only* those: emit all remaining instantiations that are required by a. Yes this is more complex, and emits a bit more than now, but it would make incremental compilation using several files at once *so much* easier. Fawzi
Oct 25 2010