www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - Unable to instantiate template with same name as function

reply Shriramana Sharma <samjnaa_dont_spam_me gmail.com> writes:
Hello. I have a function I want to make CTFE-able as a template.

string ta(string s) { return s ~ "1"; }
template ta(string s) { enum ta = ta(s); }
void main() { string s = ta!"s"; }

Compiling the above I get the errors:

<src>(2): Error: forward reference of variable ta
<src>(3): Error: template instance <src>.ta!"s" error instantiating

Please clarify what I am doing wrong? Thanks!

-- 

Mar 02 2016
next sibling parent Daniel Kozak via Digitalmars-d-learn <digitalmars-d-learn puremagic.com> writes:
Dne 3.3.2016 v 07:12 Shriramana Sharma via Digitalmars-d-learn napsal(a):
 Hello. I have a function I want to make CTFE-able as a template.

 string ta(string s) { return s ~ "1"; }
 template ta(string s) { enum ta = ta(s); }
 void main() { string s = ta!"s"; }

 Compiling the above I get the errors:

 <src>(2): Error: forward reference of variable ta
 <src>(3): Error: template instance <src>.ta!"s" error instantiating

 Please clarify what I am doing wrong? Thanks!
You cant use same name for both: import std.stdio; auto ta2(string s) { return s ~ "1"; } enum ta(string s) = ta2(s); void main() { string s = ta!"s"; writeln(s); }
Mar 02 2016
prev sibling next sibling parent reply Jonathan M Davis via Digitalmars-d-learn writes:
On Thursday, March 03, 2016 11:42:13 Shriramana Sharma via Digitalmars-d-learn 
wrote:
 Hello. I have a function I want to make CTFE-able as a template.

 string ta(string s) { return s ~ "1"; }
 template ta(string s) { enum ta = ta(s); }
 void main() { string s = ta!"s"; }

 Compiling the above I get the errors:

 <src>(2): Error: forward reference of variable ta
 <src>(3): Error: template instance <src>.ta!"s" error instantiating

 Please clarify what I am doing wrong? Thanks!
You can't overload a function and an eponymous template like that. They need to have distinct names. Now, that being said, I don't understand why you'd need to do anything with a template for CTFE in this case. Just write the function and then call it in a context that requires a compile-time result, and it should work. e.g. void main() { enum s = ta("s"); } - Jonathan M Davis
Mar 02 2016
parent reply Shriramana Sharma <samjnaa_dont_spam_me gmail.com> writes:
Hello people and thanks for your replies.

Jonathan M Davis via Digitalmars-d-learn wrote:

 You can't overload a function and an eponymous template like that. They
 need to have distinct names. 
Why is it not possible for the overload to happen? After all, the compiler should be able to identify which to use by seeing whether it is followed by ! or (), no?
 Now, that being said, I don't understand why
you'd need to do anything with a template for CTFE in this case. Just write the function and then call it in a context that requires a compile-time result, and it should work. e.g.
OK but say I have a function which returns an array. If I use enum to CTFE its result, then it is repeatedly included explicitly in all places it is used, thereby using more memory. So I want to do: string s = ta!"s"; Obviously, I can still do the different name approach, so it brings us back to the question as to why the name can't be re-used. --
Mar 03 2016
next sibling parent Daniel Kozak via Digitalmars-d-learn <digitalmars-d-learn puremagic.com> writes:
Dne 3.3.2016 v 09:58 Shriramana Sharma via Digitalmars-d-learn napsal(a):
 Hello people and thanks for your replies.

 Jonathan M Davis via Digitalmars-d-learn wrote:

 You can't overload a function and an eponymous template like that. They
 need to have distinct names.
Why is it not possible for the overload to happen? After all, the compiler should be able to identify which to use by seeing whether it is followed by ! or (), no?
 Now, that being said, I don't understand why
you'd need to do anything with a template for CTFE in this case. Just write the function and then call it in a context that requires a compile-time result, and it should work. e.g.
OK but say I have a function which returns an array. If I use enum to CTFE its result, then it is repeatedly included explicitly in all places it is used, thereby using more memory.
you can still use immutable instead of enum
Mar 03 2016
prev sibling next sibling parent reply Jonathan M Davis via Digitalmars-d-learn writes:
On Thursday, March 03, 2016 14:28:25 Shriramana Sharma via Digitalmars-d-learn 
wrote:
 Hello people and thanks for your replies.

 Jonathan M Davis via Digitalmars-d-learn wrote:
 You can't overload a function and an eponymous template like that. They
 need to have distinct names.
Why is it not possible for the overload to happen? After all, the compiler should be able to identify which to use by seeing whether it is followed by ! or (), no?
It's not legal to overload a variable and a function either. Only functions can overload functions. One symbol can shadow another if one is in a smaller scope and both aren't local variables (e.g. one is at module scope whereas the other is a local variable), but symbols at the same scope level can only overload if they're functions or templates with differing template constraints, and even then, they have to be the same thing (not one a function and the other a template). That's just the way the language is, and it does avoid certain classes of bugs.
 Now, that being said, I don't understand why
you'd need to do anything with a template for CTFE in this case. Just write the function and then call it in a context that requires a compile-time result, and it should work. e.g.
OK but say I have a function which returns an array. If I use enum to CTFE its result, then it is repeatedly included explicitly in all places it is used, thereby using more memory. So I want to do: string s = ta!"s"; Obviously, I can still do the different name approach, so it brings us back to the question as to why the name can't be re-used.
If you want a function to be called at compile time, then its result has to be assigned to something that's evaluated at compile time - like an enum. So, you can't do something like string s = ta("s"); and have it execute at compile time, and yes, having enum s = ta("s)"; and using s all over the place will result in an allocation each time that s is used. However, you can combine the two and avoid that problem. e.g. enum e = ta("s"); string s = e; The ta is run at compile time, and it's only evaluated once. In general, it's considered good practice to make something a function when you want to call it at either compile time or runtime. Then if you want to force it to be evaluated at compile time, just assign it to an enum and use that, even if you then assign it to a variable so that it doesn't get evaluated multiple times. But if you really want a template in addition to the function for whatever reason, then just name the template version something different. It may not be quite what you want, but it works just fine. - Jonathan M Davis
Mar 03 2016
parent Shriramana Sharma <samjnaa_dont_spam_me gmail.com> writes:
 AliCehreli: you may consider including Jonathan's trick in your book in the 
para above this heading: 
http://ddili.org/ders/d.en/const_and_immutable.html#ix_const_and_immutable.variable,
%20immutable

Jonathan M Davis via Digitalmars-d-learn wrote:

 yes, having
 
 enum s = ta("s)";
 
 and using s all over the place will result in an allocation each time that
 s is used. However, you can combine the two and avoid that problem. e.g.
 
 enum e = ta("s");
 string s = e;
 
 The ta is run at compile time, and it's only evaluated once.
--
Mar 04 2016
prev sibling parent reply cym13 <cpicard openmailbox.org> writes:
On Thursday, 3 March 2016 at 08:58:25 UTC, Shriramana Sharma 
wrote:
 Hello people and thanks for your replies.

 Jonathan M Davis via Digitalmars-d-learn wrote:

 You can't overload a function and an eponymous template like 
 that. They need to have distinct names.
Why is it not possible for the overload to happen? After all, the compiler should be able to identify which to use by seeing whether it is followed by ! or (), no?
Note that parentheses are optional when no argument is provided. Most functions that you use from phobos are really template functions for example but most of the time you don't use them with a template argument. So no, the compiler can't make the distinction.
Mar 03 2016
parent Shriramana Sharma <samjnaa_dont_spam_me gmail.com> writes:
cym13 wrote:

 Note that parentheses are optional when no argument is provided.
Yes I know that but the point is I expected the compiler to identify ta!"string" to refer to a different symbol than ta("string") where the one is obviously a template and the other is obviously a function call. The fact that parantheses are optional for invocations of zero-arity functions or for templates taking a single argument or able to infer its arguments is irrelevant. Anyhow, this is all moot, since actually the compiler *is* able to make the difference at the point of invocation and the problem was just a limitation in name lookup within the template itself: string ta(string s) { return s ~ "1"; } template ta(string s) { enum ta = .ta(s); } void main() { import std.stdio; writeln(ta("a"), ' ', ta!"b"); } outputs a1 b1 as expected. Filed https://issues.dlang.org/show_bug.cgi?id=15764 just for the record. --
Mar 04 2016
prev sibling parent reply ag0aep6g <anonymous example.com> writes:
On 03.03.2016 07:12, Shriramana Sharma wrote:
 string ta(string s) { return s ~ "1"; }
 template ta(string s) { enum ta = ta(s); }
In `ta(s)` here, `ta` is the enum itself again. It's similar to `int x = x;`. Can't do that, of course. Add a leading dot to refer to the module level `ta` symbols instead: `enum ta = .ta(s);`.
Mar 03 2016
parent Shriramana Sharma <samjnaa_dont_spam_me gmail.com> writes:
ag0aep6g wrote:

 On 03.03.2016 07:12, Shriramana Sharma wrote:
 string ta(string s) { return s ~ "1"; }
 template ta(string s) { enum ta = ta(s); }
In `ta(s)` here, `ta` is the enum itself again. It's similar to `int x = x;`. Can't do that, of course. Add a leading dot to refer to the module level `ta` symbols instead: `enum ta = .ta(s);`.
Wonderful! So it's just a scope issue and not a "can't do that" issue! Although it would seem that the compiler 'should' be able to identify a different kind of ta, I can't expect too much of it and the D compiler is much more powerful syntax-wise than other language compilers. I confirm that the following outputs "s1" as expected with the function call inside the template having the dot added in front: string ta(string s) { return s ~ "1"; } template ta(string s) { enum ta = .ta(s); } void main() { import std.stdio; writeln(ta!"s"); } --
Mar 04 2016