digitalmars.D.learn - specializing template with string variable in CTFE
- ketmar via Digitalmars-d-learn (29/29) Oct 26 2014 Hello.
- "Marc =?UTF-8?B?U2Now7x0eiI=?= <schuetzm gmx.net> (9/44) Oct 26 2014 Your passing the runtime parameter `fmt` as template argument.
- "Marc =?UTF-8?B?U2Now7x0eiI=?= <schuetzm gmx.net> (2/55) Oct 26 2014 Sorry, didn't read the rest of your post before replying :-P
- "Marc =?UTF-8?B?U2Now7x0eiI=?= <schuetzm gmx.net> (21/56) Oct 26 2014 Ok, I see two possibilities. The first is to make `prstr` into a
- ketmar via Digitalmars-d-learn (13/16) Oct 26 2014 but it's templated function, and it's never called in runtime, so
- "Marc =?UTF-8?B?U2Now7x0eiI=?= <schuetzm gmx.net> (12/22) Oct 26 2014 The documentation specifically says that:
- ketmar via Digitalmars-d-learn (14/26) Oct 26 2014 leaving away technical complexities for compiler writers, i like to say
- ketmar via Digitalmars-d-learn (4/19) Oct 26 2014 thank you, this is very handy. yet my desire to instantiate template
Hello. the following code is not working: template prstr(string s) { enum prstr =3D "write("~s.stringof~");\n"; } string buildWriter() (string fmt) { return prstr!(fmt[0..$-1]); } string writer(string fmt) () { enum s =3D buildWriter(fmt); return s; } void main () { import std.stdio; writeln(writer!"str"()); } z40.d(6): Error: variable fmt cannot be read at compile time z40.d(10): Error: template instance z40.buildWriter!() error instantiating z40.d(16): instantiated from here: writer!"str" but why? fmt is known in CTFE and compiler can use it as string literal for instantiating `prstr`. please, don't mind the idiocity of the code: this is just a sample to show what confuses me. i know about possibility of moving `fmt` to template argument, but i need it as function argument, 'cause `buildWriter()` actually does string processing and i want to instantiate `prstr` with the part of the string. and this processing cannot be done in 'foreach'. and writing everything in functional style sux: it leads to explosive growing of the number of arguments passed to templates.
Oct 26 2014
On Sunday, 26 October 2014 at 10:48:46 UTC, ketmar via Digitalmars-d-learn wrote:Hello. the following code is not working: template prstr(string s) { enum prstr = "write("~s.stringof~");\n"; } string buildWriter() (string fmt) { return prstr!(fmt[0..$-1]); }Your passing the runtime parameter `fmt` as template argument. Try this: string buildWriter(string fmt)() { return prstr!(fmt[0..$-1]); }string writer(string fmt) () { enum s = buildWriter(fmt);and this: enum s = buildWriter!(fmt);return s; } void main () { import std.stdio; writeln(writer!"str"()); } z40.d(6): Error: variable fmt cannot be read at compile time z40.d(10): Error: template instance z40.buildWriter!() error instantiating z40.d(16): instantiated from here: writer!"str" but why? fmt is known in CTFE and compiler can use it as string literal for instantiating `prstr`. please, don't mind the idiocity of the code: this is just a sample to show what confuses me. i know about possibility of moving `fmt` to template argument, but i need it as function argument, 'cause `buildWriter()` actually does string processing and i want to instantiate `prstr` with the part of the string. and this processing cannot be done in 'foreach'. and writing everything in functional style sux: it leads to explosive growing of the number of arguments passed to templates.
Oct 26 2014
On Sunday, 26 October 2014 at 12:27:55 UTC, Marc Schütz wrote:On Sunday, 26 October 2014 at 10:48:46 UTC, ketmar via Digitalmars-d-learn wrote:Sorry, didn't read the rest of your post before replying :-PHello. the following code is not working: template prstr(string s) { enum prstr = "write("~s.stringof~");\n"; } string buildWriter() (string fmt) { return prstr!(fmt[0..$-1]); }Your passing the runtime parameter `fmt` as template argument. Try this: string buildWriter(string fmt)() { return prstr!(fmt[0..$-1]); }string writer(string fmt) () { enum s = buildWriter(fmt);and this: enum s = buildWriter!(fmt);return s; } void main () { import std.stdio; writeln(writer!"str"()); } z40.d(6): Error: variable fmt cannot be read at compile time z40.d(10): Error: template instance z40.buildWriter!() error instantiating z40.d(16): instantiated from here: writer!"str" but why? fmt is known in CTFE and compiler can use it as string literal for instantiating `prstr`. please, don't mind the idiocity of the code: this is just a sample to show what confuses me. i know about possibility of moving `fmt` to template argument, but i need it as function argument, 'cause `buildWriter()` actually does string processing and i want to instantiate `prstr` with the part of the string. and this processing cannot be done in 'foreach'. and writing everything in functional style sux: it leads to explosive growing of the number of arguments passed to templates.
Oct 26 2014
On Sunday, 26 October 2014 at 10:48:46 UTC, ketmar via Digitalmars-d-learn wrote:Hello. the following code is not working: template prstr(string s) { enum prstr = "write("~s.stringof~");\n"; } string buildWriter() (string fmt) { return prstr!(fmt[0..$-1]); } string writer(string fmt) () { enum s = buildWriter(fmt); return s; } void main () { import std.stdio; writeln(writer!"str"()); } z40.d(6): Error: variable fmt cannot be read at compile time z40.d(10): Error: template instance z40.buildWriter!() error instantiating z40.d(16): instantiated from here: writer!"str" but why? fmt is known in CTFE and compiler can use it as string literal for instantiating `prstr`. please, don't mind the idiocity of the code: this is just a sample to show what confuses me. i know about possibility of moving `fmt` to template argument, but i need it as function argument, 'cause `buildWriter()` actually does string processing and i want to instantiate `prstr` with the part of the string. and this processing cannot be done in 'foreach'. and writing everything in functional style sux: it leads to explosive growing of the number of arguments passed to templates.Ok, I see two possibilities. The first is to make `prstr` into a normal function. You cannot use `stringof` then, but need to escape the string yourself. Luckily, std.format provides functionality for this already, albeit a bit hidden: private auto escapeStringLiteral(string s) { import std.format : formatElement, FormatSpec; import std.range : appender; auto app = appender!string; FormatSpec!char f; formatElement(app, s, f); return app.data; } The second possibility doesn't exist right now. The core problem is that the compiler needs to be able to generate runtime code for `buildWriter()`, because it's just a function after all. But there have been calls for compile-time only functions, or something along the lines of `static if(__ctfe)` (which doesn't work currently and was recently made an error). In this case, there might be a chance to allow what you want.
Oct 26 2014
On Sun, 26 Oct 2014 12:46:06 +0000 via Digitalmars-d-learn <digitalmars-d-learn puremagic.com> wrote:The second possibility doesn't exist right now. The core problem=20 is that the compiler needs to be able to generate runtime code=20 for `buildWriter()`, because it's just a function after all.but it's templated function, and it's never called in runtime, so compiler never needs to generate code for it. seems that semantic analysis prohibits such code before CTFE, and semantic analyser is completely wrong here, 'case `fmt` *can* be read in compile-time. actually, semantic analiser is wrong for any CTFE-able function in this case, and it emits completely wrong error message (compile time variable can't be read in compile time? how this can be true?). i understand that it can be hard to fix semantic analyser though. ah, but this limitation is so... limiting! not sure if it worth the ER though. people seems to not write alot of complex CTFE code anyway.
Oct 26 2014
On Sunday, 26 October 2014 at 19:32:28 UTC, ketmar via Digitalmars-d-learn wrote:On Sun, 26 Oct 2014 12:46:06 +0000 via Digitalmars-d-learn <digitalmars-d-learn puremagic.com> wrote:The documentation specifically says that: "Any functions that execute at compile time must also be executable at run time. [...] This means that the semantics of a function cannot depend on compile time values of the function." http://dlang.org/function.html I can imagine it would be difficult to implement it differently, because in effect the compiler would need to create a new instance of the function for every call, with each instance potentially being completely different (consider `static if` over CTFE runtime parameters).The second possibility doesn't exist right now. The core problem is that the compiler needs to be able to generate runtime code for `buildWriter()`, because it's just a function after all.but it's templated function, and it's never called in runtime, so compiler never needs to generate code for it.
Oct 26 2014
On Sun, 26 Oct 2014 20:16:18 +0000 via Digitalmars-d-learn <digitalmars-d-learn puremagic.com> wrote:The documentation specifically says that: "Any functions that execute at compile time must also be=20 executable at run time. [...] This means that the semantics of a=20 function cannot depend on compile time values of the function." =20 http://dlang.org/function.html =20 I can imagine it would be difficult to implement it differently,=20 because in effect the compiler would need to create a new=20 instance of the function for every call, with each instance=20 potentially being completely different (consider `static if` over=20 CTFE runtime parameters).leaving away technical complexities for compiler writers, i like to say that restrictions for templated functions can be relaxed. maybe by marking some templates/functions as "CTFE-only". or just fix semantic analyser to allow some more things in CTFE. such template will never instantiates successfully for run-time code, and it still can be used in metaprogramming. writing purely functional templates really sux. i made a simple writef-like module which parses it's format string in compile time and i must admit that some templates has 10+ arguments and keep growing as i adding features. either this, or even more convoluted hacks. alas, i'm still don't understand compiler code deep enough to see how hard this will be to implement.
Oct 26 2014
On Sun, 26 Oct 2014 12:46:06 +0000 via Digitalmars-d-learn <digitalmars-d-learn puremagic.com> wrote:Ok, I see two possibilities. The first is to make `prstr` into a=20 normal function. You cannot use `stringof` then, but need to=20 escape the string yourself. Luckily, std.format provides=20 functionality for this already, albeit a bit hidden: =20 private auto escapeStringLiteral(string s) { import std.format : formatElement, FormatSpec; import std.range : appender; =20 auto app =3D appender!string; FormatSpec!char f; formatElement(app, s, f); =20 return app.data; }thank you, this is very handy. yet my desire to instantiate template with compile-time variable still remains. ;-)
Oct 26 2014