April 18, 2017
On Tuesday, 18 April 2017 at 06:54:11 UTC, Jacob Carlborg wrote:
> On 2017-04-17 21:28, Jonas Drewsen wrote:
>
>> The page could also list pre-approved language
>> changes such as async functions (which Walter wants afaik).
>
> Another feature that can be implemented with AST macros. This is starting to get ridicules. So many features have been added and are talked about that can be implemented with AST macros instead. Same as with the scope/safe related DIPs. Many smallish specialized features are added instead of a generic feature that can handle all of them. Increasing the complexity of the language.

The corresponding ast-macros would be extremely complex, slow and worst of all not checkable.


April 18, 2017
On 2017-04-18 08:59, Stefan Koch wrote:

> The corresponding ast-macros would be extremely complex

No, it's not that complex.

>, slow and worst
> of all not checkable.

What do you mean "not checkable"?

-- 
/Jacob Carlborg
April 18, 2017
On 4/15/2017 1:04 PM, Jonas Drewsen wrote:
>[...]

Thanks for doing the work to make a sample implementation, too. I don't know if this will make it into D, but Jonas is a fine example of a champion.
April 18, 2017
On 4/15/2017 4:51 PM, cym13 wrote:
> Removing imports is a good point, the first concrete one to be mentionned. I'm
> not sure it matters that much though as I think those imports are generic enough
> that I believe they would be imported anyway, but it's a real point.

It may not be necessary to have any dependencies on any import.

    $"{a} times 3 is {a*3}"

could be rewritten by the parser to:

    "%s times 3 is %s", a, a * 3

and that is that. (I.e. just an AST rewrite.) It would be quite a bit simpler than Jonas' proposed implementation.
April 18, 2017
On 2017-04-18 10:50, Walter Bright wrote:

> It may not be necessary to have any dependencies on any import.
>
>     $"{a} times 3 is {a*3}"
>
> could be rewritten by the parser to:
>
>     "%s times 3 is %s", a, a * 3
>
> and that is that. (I.e. just an AST rewrite.) It would be quite a bit
> simpler than Jonas' proposed implementation.

Then you would be forced to wrap it in a function call, to "format" or similar. The example of using "writeln" is not the best, a more useful example is when not printing the string immediately. For example:

auto s = $"{a} times 3 is {a*3}";

With your example that would need to be written as:

import std.format;
auto s = format($"{a} times 3 is {a*3}");

-- 
/Jacob Carlborg
April 18, 2017
On Tuesday, 18 April 2017 at 08:50:07 UTC, Walter Bright wrote:
> It may not be necessary to have any dependencies on any import.
>
>     $"{a} times 3 is {a*3}"
>
> could be rewritten by the parser to:
>
>     "%s times 3 is %s", a, a * 3
>
> and that is that. (I.e. just an AST rewrite.) It would be quite a bit simpler than Jonas' proposed implementation.

For, say, sql query generator it would be nice to have a rewrite like
sql!"select name from users where id={n}"
=>
auto q=query("select name from users where id=@p0");
q.addParameter("p0",n);

pragma(autoMixin)
template sql(string txt)
{
  enum string sql=generateCode(txt);
}

If this can be rewritten as automatic string mixin like so:
sql!"select name from users where id={n}"
=>
mixin(sql!"select name from users where id={n}")
April 18, 2017
On Tuesday, 18 April 2017 at 08:50:07 UTC, Walter Bright wrote:
> On 4/15/2017 4:51 PM, cym13 wrote:
>> Removing imports is a good point, the first concrete one to be mentionned. I'm
>> not sure it matters that much though as I think those imports are generic enough
>> that I believe they would be imported anyway, but it's a real point.
>
> It may not be necessary to have any dependencies on any import.
>
>     $"{a} times 3 is {a*3}"
>
> could be rewritten by the parser to:
>
>     "%s times 3 is %s", a, a * 3
>
> and that is that. (I.e. just an AST rewrite.) It would be quite a bit simpler than Jonas' proposed implementation.

I've thought about it and decided, I like this idea.  I've only used interpolated strings in PHP which left a bad taste, but I realized that interpolating strings makes it impossible for your format string and your arguments to get out of sync. This makes interpolated strings harder to use incorrectly (Scott Meyers had a good talk on this, https://www.youtube.com/watch?v=5tg1ONG18H8).

The biggest drawback I could think of was overhead, but with an implementation like this there is NO RUNTIME OVERHEAD!  It's also simple (easy to implement and understand) and flexible (works with all existing functions that accept "format-like" arguments).

Have you thought about supporting format specifiers as well?  I looked at the C# version and it looks like they can specify them using a colon like this:

    $"{a} in hex is {a:x}"

However this may create an ambiguity in the grammar, not sure. I'm not sure what kind of expression would be supported in the braces.  If the expression supported labels then this would definitely cause ambiguity.  In the example "{a:x}", the symbol "a" could just be parsed as a label.
April 18, 2017
On Tue, Apr 18, 2017 at 09:56:28PM +0000, Jonathan Marler via Digitalmars-d wrote: [...]
> I've thought about it and decided, I like this idea.  I've only used interpolated strings in PHP which left a bad taste, but I realized that interpolating strings makes it impossible for your format string and your arguments to get out of sync. This makes interpolated strings harder to use incorrectly (Scott Meyers had a good talk on this, https://www.youtube.com/watch?v=5tg1ONG18H8).
[...]

Phobos git HEAD now supports compile-time format strings of the form:

	writefln!"My %s value is %d."("field", 123);

If your arguments are out of sync with the format string, this will abort with a compilation error. So you won't end up in the situation where the format string or arguments are wrong but you only find out when it throws a runtime exception. Or worse, in the C situation where mismatched format string / arguments can lead to stack overruns and security exploits. (Though C compilers have been hacked to check this and issue warnings. But that's veering offtopic.)

Having said that, though, there is still one problem where you can still get into trouble:

	writefln!"The date is %04d-%02d-%02d"(month, year, day);

It may not be immediately obvious that month and year have been transposed (presumably by mistake), because the %d specifier happens to work with both argument orderings. Whereas in an interpolated string, it becomes painfully obvious:

	// Using OP's tentative proposed syntax
	writeln($"The date is {month}-{year}-{day}");
	//                    ^^^^^^^^^^^^^^ mistake is obvious here

This problem may be especially prominent in D because we're used to writing %s as a general specifier that works for any argument type.


T

-- 
Long, long ago, the ancient Chinese invented a device that lets them see through walls. It was called the "window".
April 19, 2017
On 2017-04-18 23:56, Jonathan Marler wrote:
> I've thought about it and decided, I like this idea.  I've only used interpolated strings in PHP which left a bad taste, but I realized that interpolating strings makes it impossible for your format string and your arguments to get out of sync. This makes interpolated strings harder to use incorrectly (Scott Meyers had a good talk on this, https://www.youtube.com/watch?v=5tg1ONG18H8).

++

(ps. named arguments ;)

April 18, 2017
On Tuesday, 18 April 2017 at 08:01:14 UTC, Jacob Carlborg wrote:
> On 2017-04-18 08:59, Stefan Koch wrote:
>
>> The corresponding ast-macros would be extremely complex
>
> No, it's not that complex.

Here's how it's done in Nim, a statically typed language similar to D, but with Python syntax, and macros. It takes some knowledge to understand, sure, macros are not a beginner tool, but wouldn't say this is extremely complex. I bet a D-with-macros would have a similar complexity solution.

------------------------------ string_interpolation.nim ------------------------------

import macros, parseutils, sequtils

macro exho(text: string{lit}): untyped =
  var nodes: seq[NimNode] = @[]
  # Parse string literal into "stuff".
  for k, v in text.strVal.interpolatedFragments:
    if k == ikStr or k == ikDollar:
      nodes.add(newLit(v))
    else:
      nodes.add(parseExpr("$(" & v & ")"))
  # Fold individual nodes into a statement list.
  result = newNimNode(nnkStmtList).add(
    foldr(nodes, a.infix("&", b)))

const
  multiplier = 3.14
  message = exho"$multiplier times 2.5 is ${multiplier * 2.5}"
  foo = "foo"
  message2 = exho"$foo 3 times is ${foo & foo & foo}"

echo message
echo message2
--------------------------------------------------------------------------------

Running gives

3.14 times 2.5 is 7.850000000000001
foo 3 times is foofoofoo