digitalmars.D - proposal: a new string litteral to embed variables in a string
- Timothee Cour (30/30) Oct 31 2013 the proposed new syntax
- Jacob Carlborg (4/12) Oct 31 2013 Would @ be the best symbol for this. It might get confusing with UDA's.
- Timothee Cour (3/19) Oct 31 2013 $ is another obvious choice (eg in shell expansion)
- Jacob Carlborg (4/6) Nov 01 2013 Yeah, # is only used for #line, which should be less common than $.
- Timothee Cour (13/20) Nov 05 2013 actually an important use case of this feature is to help writing domain
- Daniel Davidson (7/15) Nov 05 2013 Isn't this just string interpolation which many/most languages
- Timothee Cour (14/19) Nov 05 2013 This is more powerful than string interpolation, as it generates a tuple
- Timothee Cour (2/3) Nov 05 2013 Let me try to post it soon.
- Jacob Carlborg (6/13) Nov 06 2013 If we're talking about writing other languages inside D, then "@" would
- Timothee Cour (5/18) Nov 06 2013 How about parametrizing the escape string:
- Jacob Carlborg (4/8) Nov 07 2013 Looks like this is getting quite complicated.
- Manu (10/34) Nov 05 2013 While thinking on a new string literal that may support DSL's, the synta...
- Jacob Carlborg (7/17) Nov 06 2013 Github flavored Markdown uses:
- Timothee Cour (22/31) Nov 05 2013 I agree. For that suggest the following syntax (independent of this
- Chris Cain (21/35) Nov 05 2013 I'd very nearly say that this could be a library function.
- Timothee Cour (13/49) Nov 05 2013 one problem with this:
- Timothee Cour (10/26) Oct 31 2013 btw, another argument is type safety: my proposal has type safety inheri...
- Daniel Davidson (4/15) Nov 02 2013 Would you mind posting your code?
- Dicebot (3/3) Nov 06 2013 Reasonable proposal but I have not encountered much need in this
- Gary Willoughby (4/13) Nov 06 2013 I agree.
- Dmitry Olshansky (6/9) Nov 06 2013 +1
- Manu (4/12) Nov 06 2013 Every time I use a q{} block, it's to embed some code in a different
- Dmitry Olshansky (13/26) Nov 06 2013 Depending on editor/IDE a decent macro/extension would detect specific
- Timothee Cour (5/39) Nov 06 2013 So
- Dmitry Olshansky (8/35) Nov 06 2013 AFAICT there is no universal thing (literal syntax) that mix well into
- Timothee Cour (7/17) Nov 06 2013 To those who don't see the use of this:
- Dmitry Olshansky (60/65) Nov 06 2013 Challenge accepted.
- Daniel Davidson (13/80) Nov 06 2013 That is cool, but it is not DRY. Interpolation is well
- H. S. Teoh (72/150) Nov 06 2013 [...]
- Daniel Davidson (8/23) Nov 06 2013 Good stuff.
- Timothee Cour (22/165) Nov 06 2013 As I mentioned in my OT, this is what I already have implemented ("I've
- Jacob Carlborg (5/26) Nov 07 2013 I agree with you, but I rather have a more general solution. That is,
- Timothee Cour (4/36) Nov 07 2013 I would love to have AST macros too, but how do they help for the proble...
- Jacob Carlborg (18/21) Nov 07 2013 If AST macros worked like my vision [1] then it can be done by doing
the proposed new syntax r{var1= a; and var2= foo} is replaced by a tuple: ("var1=", a, "; and var2=", foo) where denotes escaping symbols. itself be escaped with \ . optionally, expressions can be incorporated: r{a2= (a*2); and fooU= (foo.toUpper)} I've actually already implemented this feature via a mixin, and find it extremely useful, but removing the mixing via this proposal would make it even more palatable. It works using a simple grammar that searches for valid identifiers after a , or finds nested expressions nested inside parenthesis (arbitrary nesting allowed). Proper tooling will syntax highlight correctly the nested variables. This feature is especially useful when there are a few variables involved, as alternatives are clunky use cases: A) simple string formatting (eg: formattedWrite) ---- q{first var= a, second= b, third= c!}.foo vs: ("first var=",a," second=",b," third=",c,"!").foo // `",,"` for a single ` ` ("first var=%s, second=%s, third=%s!", a, b, c).foo => // error prone esp with many variables or alternatives involving ~ : ("first var="~a.to!string~", second="~b.to!string~", third="~c.to!string~"!").foo //clunky B) parsing (eg formattedRead) same advantages as above
Oct 31 2013
On 2013-10-31 22:24, Timothee Cour wrote:the proposed new syntax r{var1= a; and var2= foo} is replaced by a tuple: ("var1=", a, "; and var2=", foo) where denotes escaping symbols. itself be escaped with \ . optionally, expressions can be incorporated: r{a2= (a*2); and fooU= (foo.toUpper)}Would be the best symbol for this. It might get confusing with UDA's. -- /Jacob Carlborg
Oct 31 2013
$ is another obvious choice (eg in shell expansion) On Thu, Oct 31, 2013 at 2:37 PM, Jacob Carlborg <doob me.com> wrote:On 2013-10-31 22:24, Timothee Cour wrote:the proposed new syntax r{var1= a; and var2= foo} is replaced by a tuple: ("var1=", a, "; and var2=", foo) where denotes escaping symbols. itself be escaped with \ . optionally, expressions can be incorporated: r{a2= (a*2); and fooU= (foo.toUpper)}Would be the best symbol for this. It might get confusing with UDA's. -- /Jacob Carlborg
Oct 31 2013
On 2013-10-31 22:47, Timothee Cour wrote:$ is another obvious choice (eg in shell expansion)-- /Jacob Carlborg
Nov 01 2013
actually an important use case of this feature is to help writing domain specific language inputs, eg writing a python file inside D, or config / plain text files. would be inside string literal so should cause little confusion from D's side, but for example would force one to escape ' ' in email addresses (more rare). Frankly, this is bike shedding though; let's assume we pick one in http://www.ascii-code.com/ and focus on whether we can agree on this feature. I'm using it extensively for great benefit: more DRY code, less spurious files, cleaner integration with D. On Fri, Nov 1, 2013 at 12:33 AM, Jacob Carlborg <doob me.com> wrote:On 2013-10-31 22:47, Timothee Cour wrote:$ is another obvious choice (eg in shell expansion)-- /Jacob Carlborg
Nov 05 2013
On Tuesday, 5 November 2013 at 22:26:23 UTC, Timothee Cour wrote:Frankly, this is bike shedding though; let's assume we pick one in http://www.ascii-code.com/ and focus on whether we can agree on this feature. I'm using it extensively for great benefit: more DRY code, less spurious files, cleaner integration with D.Isn't this just string interpolation which many/most languages have? Yes - it is a great feature. Do you have working code on github that others may use? Thanks Dan
Nov 05 2013
On Tue, Nov 5, 2013 at 3:19 PM, Daniel Davidson <nospam spam.com> wrote:Isn't this just string interpolation which many/most languages have? Yes - it is a great feature. Do you have working code on github that others may use? Thanks DanThis is more powerful than string interpolation, as it generates a tuple instead of generating a string: in my proposal, r{var1= a; and var2= foo} is replaced by ("var1=", a, "; and var2=", foo) instead of text("var1=,a,"; and var2=",foo), as done in most languages like you mention. This exploits D's powerful variadic templates and is more powerful: we can get string interpolation by simply using r{...}.text but we can do more fancy things if needed (eg apply formatting, etc), without requiring additional types of string litterals, as needed in scala ( http://docs.scala-lang.org/overviews/core/string-interpolation.html)
Nov 05 2013
On Tue, Nov 5, 2013 at 3:19 PM, Daniel Davidson <nospam spam.com> wrote:Do you have working code on github that others may use?Let me try to post it soon.
Nov 05 2013
On 2013-11-05 23:26, Timothee Cour wrote:actually an important use case of this feature is to help writing domain specific language inputs, eg writing a python file inside D, or config / plain text files. would be inside string literal so should cause little confusion from D's side, but for example would force one to escape ' ' in email addresses (more rare).If we're talking about writing other languages inside D, then " " would be in conflict with Objective-C which uses that for all new syntax (that isn't available in plain C). -- /Jacob Carlborg
Nov 06 2013
On Wed, Nov 6, 2013 at 2:43 AM, Jacob Carlborg <doob me.com> wrote:On 2013-11-05 23:26, Timothee Cour wrote:How about parametrizing the escape string: r{var= a} // by default r{ }{var= a} //same as above r{$}{var=$a} //same as aboveactually an important use case of this feature is to help writing domain specific language inputs, eg writing a python file inside D, or config / plain text files. would be inside string literal so should cause little confusion from D's side, but for example would force one to escape ' ' in email addresses (more rare).If we're talking about writing other languages inside D, then " " would be in conflict with Objective-C which uses that for all new syntax (that isn't available in plain C).
Nov 06 2013
On 2013-11-06 21:33, Timothee Cour wrote:How about parametrizing the escape string: r{var= a} // by default r{ }{var= a} //same as above r{$}{var=$a} //same as aboveLooks like this is getting quite complicated. -- /Jacob Carlborg
Nov 07 2013
While thinking on a new string literal that may support DSL's, the syntax should optionally receive a language specification on opening. The thing that sucks most about DSL's is that the IDE can't syntax hilight them, but if it was provided what language the string was, then a smart IDE could apply syntax hilighting for that language within the scring scope. Eg, this sort of thing is supported in html, which is usually hilighted correctly by IDE's: <script type="text/javascript"> or <script language="javascript"> And exists in many other places too. On 6 November 2013 08:26, Timothee Cour <thelastmammoth gmail.com> wrote:actually an important use case of this feature is to help writing domain specific language inputs, eg writing a python file inside D, or config / plain text files. would be inside string literal so should cause little confusion from D's side, but for example would force one to escape ' ' in email addresses (more rare). Frankly, this is bike shedding though; let's assume we pick one in http://www.ascii-code.com/ and focus on whether we can agree on this feature. I'm using it extensively for great benefit: more DRY code, less spurious files, cleaner integration with D. On Fri, Nov 1, 2013 at 12:33 AM, Jacob Carlborg <doob me.com> wrote:On 2013-10-31 22:47, Timothee Cour wrote:$ is another obvious choice (eg in shell expansion)-- /Jacob Carlborg
Nov 05 2013
On 2013-11-06 02:42, Manu wrote:While thinking on a new string literal that may support DSL's, the syntax should optionally receive a language specification on opening. The thing that sucks most about DSL's is that the IDE can't syntax hilight them, but if it was provided what language the string was, then a smart IDE could apply syntax hilighting for that language within the scring scope. Eg, this sort of thing is supported in html, which is usually hilighted correctly by IDE's: <script type="text/javascript"> or <script language="javascript"> And exists in many other places too.Github flavored Markdown uses: ```javascript // JavaScript code ``` -- /Jacob Carlborg
Nov 06 2013
On Tue, Nov 5, 2013 at 5:42 PM, Manu <turkeyman gmail.com> wrote:While thinking on a new string literal that may support DSL's, the syntax should optionally receive a language specification on opening. The thing that sucks most about DSL's is that the IDE can't syntax hilight them, but if it was provided what language the string was, then a smart IDE could apply syntax hilighting for that language within the scring scope. Eg, this sort of thing is supported in html, which is usually hilighted correctly by IDE's: <script type="text/javascript"> or <script language="javascript"> And exists in many other places too.I agree. For that suggest the following syntax (independent of this proposal): That is, support UDA for expressions. ---- void main(){ import std.conv:text; int var=12; ("syntax=python") r{ def fun: print( var) #will expand to tuple element 12 print( (var.to!string)) #will expand to tuple element "12" } .text .run_python; void run_python(string a){ import std.system; system("python -c "~a.escapeShellFileName); } } ----
Nov 05 2013
On Wednesday, 6 November 2013 at 02:38:57 UTC, Timothee Cour wrote:I agree. For that suggest the following syntax (independent of this proposal): That is, support UDA for expressions. ---- void main(){ import std.conv:text; int var=12; ("syntax=python") r{ ...snip... } } ----I'd very nearly say that this could be a library function. Imagine it like this: --- syntax!"python"(r{ ... }) --- A bit more verbose than using a UDA but the return type could be something like SyntaxType!"python" and you could make it so that functions only take SyntaxType!"python" for some compile-time checking using the type system. For instance, if your function requires python code then you can specify it in the argument. I'd also like it to be implicitly convertable to a generic SyntaxType that accepts everything if you just don't care what kind of syntax it is. As long as it's part of the standard library, then IDEs could also take advantage of it. Not saying that they shouldn't also support UDAs, but just throwing that out there as another alternative.
Nov 05 2013
On Tue, Nov 5, 2013 at 7:43 PM, Chris Cain <clcain uncg.edu> wrote:On Wednesday, 6 November 2013 at 02:38:57 UTC, Timothee Cour wrote:one problem with this: r{...} is converted to a built-in tuple, and we can't return built-in tuples from functions (only std.typecons.tuple, which has issues, eg unnecessary copying, can't return elements by ref, etc). Note that returning elements by ref (when needed) is crucial for use case B in the OT (formattedRead). On the otherhand, I also thought about using a modification of std.typetuple.Alias that gets an extra 1st argument to indicate syntax. It doesn't work because when there's an expression involved we get: Error: variable a cannot be read at compile time; eg: Alias!(a+b,"foo") and r{...} syntax is suppose to support arbitrary expressions and forward them as builtin tuple.I agree. For that suggest the following syntax (independent of this proposal): That is, support UDA for expressions. ---- void main(){ import std.conv:text; int var=12; ("syntax=python") r{ ...snip... } } ----I'd very nearly say that this could be a library function. Imagine it like this: --- syntax!"python"(r{ ... }) --- A bit more verbose than using a UDA but the return type could be something like SyntaxType!"python" and you could make it so that functions only take SyntaxType!"python" for some compile-time checking using the type system. For instance, if your function requires python code then you can specify it in the argument. I'd also like it to be implicitly convertable to a generic SyntaxType that accepts everything if you just don't care what kind of syntax it is. As long as it's part of the standard library, then IDEs could also take advantage of it. Not saying that they shouldn't also support UDAs, but just throwing that out there as another alternative.
Nov 05 2013
btw, another argument is type safety: my proposal has type safety inherited from typesafe variadic templates, whereas the "%s" way of doing things is fragile: import std.stdio; void main(){ writefln("%s%s%s\n",1,2);//crash at RT writefln("%s%s\n",1,2,3);//silently accepts even though 1 more argument writefln("%s%d\n",1,"foo");//crash at RT: wrong format specifier } On Thu, Oct 31, 2013 at 2:37 PM, Jacob Carlborg <doob me.com> wrote:On 2013-10-31 22:24, Timothee Cour wrote:the proposed new syntax r{var1= a; and var2= foo} is replaced by a tuple: ("var1=", a, "; and var2=", foo) where denotes escaping symbols. itself be escaped with \ . optionally, expressions can be incorporated: r{a2= (a*2); and fooU= (foo.toUpper)}Would be the best symbol for this. It might get confusing with UDA's. -- /Jacob Carlborg
Oct 31 2013
On Thursday, 31 October 2013 at 21:24:42 UTC, Timothee Cour wrote:I've actually already implemented this feature via a mixin, and find it extremely useful, but removing the mixing via this proposal would make it even more palatable. It works using a simple grammar that searches for valid identifiers after a , or finds nested expressions nested inside parenthesis (arbitrary nesting allowed). Proper tooling will syntax highlight correctly the nested variables.Would you mind posting your code? Thanks Dan
Nov 02 2013
Reasonable proposal but I have not encountered much need in this functionality personally (std.string.format worked just fine) and thus can't really evaluate how justified such addition may be.
Nov 06 2013
On Wednesday, 6 November 2013 at 03:44:07 UTC, Chris Cain wrote:I'd very nearly say that this could be a library function. Imagine it like this: syntax!"python"(r{ ... })I agree. On Wednesday, 6 November 2013 at 11:45:41 UTC, Dicebot wrote:Reasonable proposal but I have not encountered much need in this functionality personally (std.string.format worked just fine) and thus can't really evaluate how justified such addition may be.I also agree.
Nov 06 2013
06-Nov-2013 15:45, Dicebot пишет:Reasonable proposal but I have not encountered much need in this functionality personally (std.string.format worked just fine) and thus can't really evaluate how justified such addition may be.+1 Since formatting/templates became accessible in CTFE I do not see much need for this. -- Dmitry Olshansky
Nov 06 2013
On 7 November 2013 03:14, Dmitry Olshansky <dmitry.olsh gmail.com> wrote:06-Nov-2013 15:45, Dicebot =D0=BF=D0=B8=D1=88=D0=B5=D1=82: Reasonable proposal but I have not encountered much need in thisEvery time I use a q{} block, it's to embed some code in a different language. I would like the IDE to syntax hilight properly if able. HLSL/GLSL, JSON, XML are the most common embedded languages I encounter.functionality personally (std.string.format worked just fine) and thus can't really evaluate how justified such addition may be.+1 Since formatting/templates became accessible in CTFE I do not see much need for this.
Nov 06 2013
06-Nov-2013 21:40, Manu пишет:On 7 November 2013 03:14, Dmitry Olshansky <dmitry.olsh gmail.com <mailto:dmitry.olsh gmail.com>> wrote: 06-Nov-2013 15:45, Dicebot пишет: Reasonable proposal but I have not encountered much need in this functionality personally (std.string.format worked just fine) and thus can't really evaluate how justified such addition may be. +1 Since formatting/templates became accessible in CTFE I do not see much need for this. Every time I use a q{} block, it's to embed some code in a different language. I would like the IDE to syntax hilight properly if able. HLSL/GLSL, JSON, XML are the most common embedded languages I encounter.Depending on editor/IDE a decent macro/extension would detect specific function before the q{}. Say: hlsl!q{ }; And highlight it as appropriate. I think it's customary for good editors to highlight parts of code based on different scheme (say PHP/JS mixed in the HTML highlights just fine). So the basic blocks must be there already. All in all it's hardly a good thing to trade a language feature *only* to help people give "hints" to IDEs (which they may as well ignore). -- Dmitry Olshansky
Nov 06 2013
On Wed, Nov 6, 2013 at 10:49 AM, Dmitry Olshansky <dmitry.olsh gmail.com>wr= ote:06-Nov-2013 21:40, Manu =D0=C9=DB=C5=D4:SoOn 7 November 2013 03:14, Dmitry Olshansky <dmitry.olsh gmail.com <mailto:dmitry.olsh gmail.com>> wrote: 06-Nov-2013 15:45, Dicebot =D0=C9=DB=C5=D4: Reasonable proposal but I have not encountered much need in this functionality personally (std.string.format worked just fine) and thus can't really evaluate how justified such addition may be. +1 Since formatting/templates became accessible in CTFE I do not see much need for this. Every time I use a q{} block, it's to embed some code in a different language. I would like the IDE to syntax hilight properly if able. HLSL/GLSL, JSON, XML are the most common embedded languages I encounter.Depending on editor/IDE a decent macro/extension would detect specific function before the q{}. Say: hlsl!q{ }; And highlight it as appropriate. I think it's customary for good editors to highlight parts of code based on different scheme (say PHP/JS mixed in the HTML highlights just fine). =the basic blocks must be there already. All in all it's hardly a good thing to trade a language feature *only* to help people give "hints" to IDEs (which they may as well ignore).the proposal in the OT is not about syntax highlight hints, it's about embedding variables in string literals.-- Dmitry Olshansky
Nov 06 2013
07-Nov-2013 00:24, Timothee Cour ÐÉÛÅÔ:On Wed, Nov 6, 2013 at 10:49 AM, Dmitry Olshansky <dmitry.olsh gmail.com <mailto:dmitry.olsh gmail.com>> wrote: 06-Nov-2013 21:40, Manu ÐÉÛÅÔ: On 7 November 2013 03:14, Dmitry Olshansky <dmitry.olsh gmail.com <mailto:dmitry.olsh gmail.com> <mailto:dmitry.olsh gmail.com <mailto:dmitry.olsh gmail.com>>__> wrote: 06-Nov-2013 15:45, Dicebot ÐÉÛÅÔ: Reasonable proposal but I have not encountered much need in this functionality personally (std.string.format worked just fine) and thus can't really evaluate how justified such addition may be. +1 Since formatting/templates became accessible in CTFE I do not see much need for this. Every time I use a q{} block, it's to embed some code in a different language. I would like the IDE to syntax hilight properly if able. HLSL/GLSL, JSON, XML are the most common embedded languages I encounter.[snip]All in all it's hardly a good thing to trade a language feature *only* to help people give "hints" to IDEs (which they may as well ignore). the proposal in the OT is not about syntax highlight hints, it's about embedding variables in string literals.AFAICT there is no universal thing (literal syntax) that mix well into every DSL. On this fact alone I'd rather use a natural template engine for the DSL in question. That and fact that it's a whole new feature with its pitfalls is enough for me to at least postpone it. -- Dmitry Olshansky
Nov 06 2013
To those who don't see the use of this: which code would you rather read & write? see pastebin: http://dpaste.dzfl.pl/b9f65a39 Another advantage is that using an autoformatter won't mess up things inside a r{..} literal. On Wed, Nov 6, 2013 at 9:14 AM, Dmitry Olshansky <dmitry.olsh gmail.com>wro= te:06-Nov-2013 15:45, Dicebot =D0=BF=D0=B8=D1=88=D0=B5=D1=82: Reasonable proposal but I have not encountered much need in thisfunctionality personally (std.string.format worked just fine) and thus can't really evaluate how justified such addition may be.+1 Since formatting/templates became accessible in CTFE I do not see much need for this. -- Dmitry Olshansky
Nov 06 2013
07-Nov-2013 01:02, Timothee Cour пишет:To those who don't see the use of this: which code would you rather read & write? see pastebin: http://dpaste.dzfl.pl/b9f65a39 Another advantage is that using an autoformatter won't mess up things inside a r{..} literal.Challenge accepted. 50 lines in current D2: import std.algorithm, std.conv, std.array, std.uni, std.stdio; auto embed(Vars...)(string tmpl) { auto app = appender!string(); alias Put = void delegate(); Put[string] fns; foreach(i, v; Vars) { //strangely v.stringof is "v" - BUG/FEATURE ? :) //may do better then to!string fns[Vars[i].stringof] = (){ app.put(to!string(v)); }; } auto slice = tmpl; while(!slice.empty) { auto anchor = find(slice, ' '); app.put(slice[0..$-anchor.length]); if(anchor.empty) break; slice = find!(a => !isAlpha(a))(anchor[1..$]); auto name = anchor[1..$-slice.length]; if(!slice.empty) { if(name in fns) fns[name](); } } return app.data; } void main(){ int a = 2; float b = 3.14; string c = "hello"; auto x = q{var= a, second= b, third= c!}.embed!(a,b,c); writeln(x); int age = 45; string address = "Fleet st. 15"; dstring fieldName = "my_field"; auto y = q{ "firstName": " firstName", "age": age, "address": { fieldName: " address", } }.embed!(age, fieldName, address); writeln(y); } Prints as expected: var=2, second=3.14, third=hello! "firstName": "", "age": 45, "address": { my_field: "Fleet st. 15", } Now isn't it already nice beyond proportions? -- Dmitry Olshansky
Nov 06 2013
On Wednesday, 6 November 2013 at 21:37:14 UTC, Dmitry Olshansky wrote:07-Nov-2013 01:02, Timothee Cour пишет:That is cool, but it is not DRY. Interpolation is well established and clearly adds value - else why would almost every language provide it? You should not have to pass (age, fieldName, address) into it - since it already has it in the string. That is the real challenge, get those variables and interpolate them. Maybe I am missing something, but the format approach advocated by you and dicebot means breaking up strings (ugly and potentially error prone) and/or repeating yourself. Thanks DanTo those who don't see the use of this: which code would you rather read & write? see pastebin: http://dpaste.dzfl.pl/b9f65a39 Another advantage is that using an autoformatter won't mess up things inside a r{..} literal.Challenge accepted. 50 lines in current D2: import std.algorithm, std.conv, std.array, std.uni, std.stdio; auto embed(Vars...)(string tmpl) { auto app = appender!string(); alias Put = void delegate(); Put[string] fns; foreach(i, v; Vars) { //strangely v.stringof is "v" - BUG/FEATURE ? :) //may do better then to!string fns[Vars[i].stringof] = (){ app.put(to!string(v)); }; } auto slice = tmpl; while(!slice.empty) { auto anchor = find(slice, ' '); app.put(slice[0..$-anchor.length]); if(anchor.empty) break; slice = find!(a => !isAlpha(a))(anchor[1..$]); auto name = anchor[1..$-slice.length]; if(!slice.empty) { if(name in fns) fns[name](); } } return app.data; } void main(){ int a = 2; float b = 3.14; string c = "hello"; auto x = q{var= a, second= b, third= c!}.embed!(a,b,c); writeln(x); int age = 45; string address = "Fleet st. 15"; dstring fieldName = "my_field"; auto y = q{ "firstName": " firstName", "age": age, "address": { fieldName: " address", } }.embed!(age, fieldName, address); writeln(y); } Prints as expected: var=2, second=3.14, third=hello! "firstName": "", "age": 45, "address": { my_field: "Fleet st. 15", } Now isn't it already nice beyond proportions?
Nov 06 2013
On Wed, Nov 06, 2013 at 10:50:35PM +0100, Daniel Davidson wrote:On Wednesday, 6 November 2013 at 21:37:14 UTC, Dmitry Olshansky wrote:[...][...] Challenge accepted. ;-) Here is an adaptation of Dmitri's code that doesn't require you to explicitly pass in variables: import std.algorithm; import std.array; import std.stdio; import std.uni; string interpolate(string fmt) { // The bulk of this code is copied from Dmitri's version; // thanks, Dmitri! auto app = appender!string(); app.put("\""); auto slice = fmt; while (!slice.empty) { auto anchor = find(slice, ' '); // Escape unsafe characters foreach(c; slice[0..$-anchor.length]) { if (c == '\"') app.put("\\\""); else app.put(c); } if (anchor.empty) break; slice = find!(a => !isAlpha(a))(anchor[1..$]); auto name = anchor[1..$-slice.length]; if (!slice.empty) { app.put("\"~" ~ name ~ "~\""); } } app.put("\""); return app.data; } void main() { string a = "aye"; string b = "bee"; string c = "cee"; writeln(mixin(interpolate(q{ "myobject" : { "fieldA": " a", "fieldB": " b", "fieldC": " c", } }))); } Here's the output: "myobject" : { "fieldA": "aye", "fieldB": "bee", "fieldC": "cee", } Is that acceptable to you? :) Of course, the above code is just a proof-of-concept; it doesn't handle integer or other types of variables, and it currently only escapes '"', (it should be extended to also escape '\', etc.). But all of these would be easily addressed by a proper implementation using std.conv and by handling metacharacters properly. The point is that you *can* do string interpolation in D without needing language-level support. T -- May you live all the days of your life. -- Jonathan SwiftChallenge accepted. 50 lines in current D2: import std.algorithm, std.conv, std.array, std.uni, std.stdio; auto embed(Vars...)(string tmpl) { auto app = appender!string(); alias Put = void delegate(); Put[string] fns; foreach(i, v; Vars) { //strangely v.stringof is "v" - BUG/FEATURE ? :) //may do better then to!string fns[Vars[i].stringof] = (){ app.put(to!string(v)); }; } auto slice = tmpl; while(!slice.empty) { auto anchor = find(slice, ' '); app.put(slice[0..$-anchor.length]); if(anchor.empty) break; slice = find!(a => !isAlpha(a))(anchor[1..$]); auto name = anchor[1..$-slice.length]; if(!slice.empty) { if(name in fns) fns[name](); } } return app.data; } void main(){ int a = 2; float b = 3.14; string c = "hello"; auto x = q{var= a, second= b, third= c!}.embed!(a,b,c); writeln(x); int age = 45; string address = "Fleet st. 15"; dstring fieldName = "my_field"; auto y = q{ "firstName": " firstName", "age": age, "address": { fieldName: " address", } }.embed!(age, fieldName, address); writeln(y); } Prints as expected: var=2, second=3.14, third=hello! "firstName": "", "age": 45, "address": { my_field: "Fleet st. 15", } Now isn't it already nice beyond proportions?That is cool, but it is not DRY. Interpolation is well established and clearly adds value - else why would almost every language provide it? You should not have to pass (age, fieldName, address) into it - since it already has it in the string. That is the real challenge, get those variables and interpolate them. Maybe I am missing something, but the format approach advocated by you and dicebot means breaking up strings (ugly and potentially error prone) and/or repeating yourself.
Nov 06 2013
On Wednesday, 6 November 2013 at 22:33:36 UTC, H. S. Teoh wrote:Challenge accepted. ;-) Here is an adaptation of Dmitri's code that doesn't require you to explicitly pass in variables:...Is that acceptable to you? :)Good stuff.Of course, the above code is just a proof-of-concept; it doesn't handle integer or other types of variables, and it currently only escapes '"', (it should be extended to also escape '\', etc.). But all of these would be easily addressed by a proper implementation using std.conv and by handling metacharacters properly. The point is that you *can* do string interpolation in D without needing language-level support.Absolutely - I was not under the impression it needed to be provided by the language proper. But a standard library would be nice. I look forward to seeing/using Timothy's version when it is ready. Lack of interpolation is one reason I went with Dart for my code generation tasks.
Nov 06 2013
On Wed, Nov 6, 2013 at 2:32 PM, H. S. Teoh <hsteoh quickfur.ath.cx> wrote:On Wed, Nov 06, 2013 at 10:50:35PM +0100, Daniel Davidson wrote:As I mentioned in my OT, this is what I already have implemented ("I've actually already implemented this feature via a mixin, and find it extremely useful, but ... "); and I did take care of proper escaping, etc. I am using it extensively, however the requirement for using a mixin makes things uglier than they should: * cryptic ctfe error msgs upon wrong variable names * mixin can't be used in UFCS chains; additional () nesting to the point that I only use it in cases where the alternative is uglier. * potentially more strain on ctfe * mixins in general should be used sparingly Sure we can use existing mixins to fill this need, but to me this is exactly the same as the situation with lambda literal syntax: a=>a*2 instead of (a){return a*2;} or lazy parameters: void fun(lazy string a) vs: void fun(string delegate() a) A little of syntax sugar can provide huge benifits. It's use case would apply to all assert error messages, DSLs etc.On Wednesday, 6 November 2013 at 21:37:14 UTC, Dmitry Olshansky wrote:[...][...] Challenge accepted. ;-) Here is an adaptation of Dmitri's code that doesn't require you to explicitly pass in variables: import std.algorithm; import std.array; import std.stdio; import std.uni; string interpolate(string fmt) { // The bulk of this code is copied from Dmitri's version; // thanks, Dmitri! auto app = appender!string(); app.put("\""); auto slice = fmt; while (!slice.empty) { auto anchor = find(slice, ' '); // Escape unsafe characters foreach(c; slice[0..$-anchor.length]) { if (c == '\"') app.put("\\\""); else app.put(c); } if (anchor.empty) break; slice = find!(a => !isAlpha(a))(anchor[1..$]); auto name = anchor[1..$-slice.length]; if (!slice.empty) { app.put("\"~" ~ name ~ "~\""); } } app.put("\""); return app.data; } void main() { string a = "aye"; string b = "bee"; string c = "cee"; writeln(mixin(interpolate(q{ "myobject" : { "fieldA": " a", "fieldB": " b", "fieldC": " c", } }))); } Here's the output: "myobject" : { "fieldA": "aye", "fieldB": "bee", "fieldC": "cee", } Is that acceptable to you? :) Of course, the above code is just a proof-of-concept; it doesn't handle integer or other types of variables, and it currently only escapes '"', (it should be extended to also escape '\', etc.). But all of these would be easily addressed by a proper implementation using std.conv and by handling metacharacters properly. The point is that you *can* do string interpolation in D without needing language-level support.Challenge accepted. 50 lines in current D2: import std.algorithm, std.conv, std.array, std.uni, std.stdio; auto embed(Vars...)(string tmpl) { auto app = appender!string(); alias Put = void delegate(); Put[string] fns; foreach(i, v; Vars) { //strangely v.stringof is "v" - BUG/FEATURE ? :) //may do better then to!string fns[Vars[i].stringof] = (){ app.put(to!string(v)); }; } auto slice = tmpl; while(!slice.empty) { auto anchor = find(slice, ' '); app.put(slice[0..$-anchor.length]); if(anchor.empty) break; slice = find!(a => !isAlpha(a))(anchor[1..$]); auto name = anchor[1..$-slice.length]; if(!slice.empty) { if(name in fns) fns[name](); } } return app.data; } void main(){ int a = 2; float b = 3.14; string c = "hello"; auto x = q{var= a, second= b, third= c!}.embed!(a,b,c); writeln(x); int age = 45; string address = "Fleet st. 15"; dstring fieldName = "my_field"; auto y = q{ "firstName": " firstName", "age": age, "address": { fieldName: " address", } }.embed!(age, fieldName, address); writeln(y); } Prints as expected: var=2, second=3.14, third=hello! "firstName": "", "age": 45, "address": { my_field: "Fleet st. 15", } Now isn't it already nice beyond proportions?That is cool, but it is not DRY. Interpolation is well established and clearly adds value - else why would almost every language provide it? You should not have to pass (age, fieldName, address) into it - since it already has it in the string. That is the real challenge, get those variables and interpolate them. Maybe I am missing something, but the format approach advocated by you and dicebot means breaking up strings (ugly and potentially error prone) and/or repeating yourself.T -- May you live all the days of your life. -- Jonathan Swift
Nov 06 2013
On 2013-11-06 23:48, Timothee Cour wrote:As I mentioned in my OT, this is what I already have implemented ("I've actually already implemented this feature via a mixin, and find it extremely useful, but ... "); and I did take care of proper escaping, etc. I am using it extensively, however the requirement for using a mixin makes things uglier than they should: * cryptic ctfe error msgs upon wrong variable names * mixin can't be used in UFCS chains; additional () nesting to the point that I only use it in cases where the alternative is uglier. * potentially more strain on ctfe * mixins in general should be used sparingly Sure we can use existing mixins to fill this need, but to me this is exactly the same as the situation with lambda literal syntax: a=>a*2 instead of (a){return a*2;} or lazy parameters: void fun(lazy string a) vs: void fun(string delegate() a) A little of syntax sugar can provide huge benifits. It's use case would apply to all assert error messages, DSLs etc.I agree with you, but I rather have a more general solution. That is, AST macros. -- /Jacob Carlborg
Nov 07 2013
On Thu, Nov 7, 2013 at 2:27 AM, Jacob Carlborg <doob me.com> wrote:On 2013-11-06 23:48, Timothee Cour wrote: As I mentioned in my OT, this is what I already have implemented ("I'veI would love to have AST macros too, but how do they help for the problem at hand? (eg use cases in OT + DSL). Like others mentioned, the feature is not crazy, it is present in most languages.actually already implemented this feature via a mixin, and find it extremely useful, but ... "); and I did take care of proper escaping, etc. I am using it extensively, however the requirement for using a mixin makes things uglier than they should: * cryptic ctfe error msgs upon wrong variable names * mixin can't be used in UFCS chains; additional () nesting to the point that I only use it in cases where the alternative is uglier. * potentially more strain on ctfe * mixins in general should be used sparingly Sure we can use existing mixins to fill this need, but to me this is exactly the same as the situation with lambda literal syntax: a=>a*2 instead of (a){return a*2;} or lazy parameters: void fun(lazy string a) vs: void fun(string delegate() a) A little of syntax sugar can provide huge benifits. It's use case would apply to all assert error messages, DSLs etc.I agree with you, but I rather have a more general solution. That is, AST macros.-- /Jacob Carlborg
Nov 07 2013
On 2013-11-07 12:05, Timothee Cour wrote:I would love to have AST macros too, but how do they help for the problem at hand? (eg use cases in OT + DSL). Like others mentioned, the feature is not crazy, it is present in most languages.If AST macros worked like my vision [1] then it can be done by doing something like this. The declaration of the macro would look like this: macro interpolate (Context context, Ast!(string) str) * Scan "str" for occurrences of $variableName and $(expression) or whatever syntax is chosen * Replace all occurrences with "%s" * Create the following AST: format(replacedStr, variableName, expression); Use it like: int a = 3; int b = 4; auto str = interpolate("a=$a b=$b"); Will generate the same AST as: auto str = format("a=%s b=%s", a, b); [1] https://dl.dropboxusercontent.com/u/18386187/ast_macros.html -- /Jacob Carlborg
Nov 07 2013