November 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
November 06, 2013
On Wed, Nov 6, 2013 at 10:49 AM, Dmitry Olshansky <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>> 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).


the proposal in the OT is not about syntax highlight hints, it's about embedding variables in string literals.


>
>
> --
> Dmitry Olshansky
>


November 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:
>
>> 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.
>> # is common in many languages (eg python/bash etc) as a comment.
>>
>> @ 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).
>
>
How about parametrizing the escape string:
r{var=@a} //@ by default
r{@}{var=@a} //same as above
r{$}{var=$a} //same as above


November 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
November 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>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.
>
> --
> Dmitry Olshansky
>


November 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
November 06, 2013
On Wednesday, 6 November 2013 at 21:37:14 UTC, Dmitry Olshansky wrote:
> 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?

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
Dan
November 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.
> >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.
[...]

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 Swift
November 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:
> > On Wednesday, 6 November 2013 at 21:37:14 UTC, Dmitry Olshansky wrote:
> [...]
> > >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.
> [...]
>
> 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.
>
>
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.





>
> T
>
> --
> May you live all the days of your life. -- Jonathan Swift
>


November 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.