December 08, 2018
On Saturday, 8 December 2018 at 19:17:26 UTC, Martin Tschierschke wrote:
> writeln(i!"foo #{a}".mixin) // which is not to far away from

I don't like one-letter methods/templates that can easily clash with local variables.

foreach(i; 0..10) writeln(i!"oops!".mixin);
December 08, 2018
On Saturday, 8 December 2018 at 19:47:42 UTC, Dennis wrote:
> On Saturday, 8 December 2018 at 19:17:26 UTC, Martin Tschierschke wrote:
>> writeln(i!"foo #{a}".mixin) // which is not to far away from
>
> I don't like one-letter methods/templates that can easily clash with local variables.
>
> foreach(i; 0..10) writeln(i!"oops!".mixin);

You are right using only i would clash easily, but my main question was, why it is not allowed to use .mixin ?


December 08, 2018
On Saturday, 8 December 2018 at 19:17:26 UTC, Martin Tschierschke wrote:
> I am referring to this post, because it is the first mentioning the mixin way in this thread:
>
>           Why is mixin() not allowed in UFCS?

Because mixin isn't a function, it's a special type of expression (like `sizeof` is in C). UFCS only applies to functions.

Here's the relevant part of the language specification: https://dlang.org/spec/expression.html#mixin_expressions
December 10, 2018
On Thursday, 6 December 2018 at 16:19:12 UTC, Steven Schveighoffer wrote:
> On 12/6/18 4:01 AM, Dennis wrote:
>> On Thursday, 6 December 2018 at 02:14:12 UTC, Neia Neutuladh wrote:
>>> However, that would also force druntime to include formatting code that it currently lacks.
>> 
>> Jonathan Marler's implementation [1] has a really nice approach of lowering interpolated strings to tuples. You can pass it to variadic functions like `writeln` or `text` and bring your own formatting / memory allocation schemes, giving better performance and flexibility.
>> 
>> [1] https://github.com/dlang/dmd/pull/7988
>
> I supported the concept[1] back when I read it from Dmitry Olshansky[2].
>
> If I had known about the debate on the PR I would have jumped in. But I don't have much to add. All that really dictates my views is the experience I've had with other languages. However, none of those other languages have the same concept that I know of -- they basically just create a string with toString-ing the interpolations.
>
> With the concept of lowering to a tuple, I'd love to use such a thing for database queries.
>
> For instance:
>
> db.exec("UPDATE Foo SET a = ?, b = ?, c = ?, d = ? WHERE id = ?", aval, bval, cval, dval, id);
>
> vs.
>
> db.exec(i"UPDATE Foo SET a = $aval, b = $bval, c = $cval, d = $dval WHERE id = $id");
>
> The mixin/library solution is much less approachable. What's awesome about the language solution is that it just works without much extra understanding and verbosity, and need for using mixins. mixins are cool, but are best tucked away behind templates or generative functions. They shouldn't seen much in user code. Saying we should use a library solution for this is like saying we can replace foreach usage with a library foreach that lowers to some for-loop and explicit delegates (or maybe a mixin?). Yes, it could be done. No, it shouldn't be done. This is one of those types of syntax sugar that should not be ignored.
>
> +1000 from me, I'd love to see the PR merged, or the DIP created, whatever needs to happen.
>
> -Steve
>
> [1] https://forum.dlang.org/post/odb9hk$2jqm$1@digitalmars.com
> [2] https://forum.dlang.org/post/ocut06$261n$1@digitalmars.com

Can you add some examples/explanations about the database querying to the DIP?
December 09, 2018
On Sat, Dec 08, 2018 at 05:17:13PM +0000, o via Digitalmars-d wrote:
> On Saturday, 8 December 2018 at 02:29:10 UTC, Steven Schveighoffer wrote:
> > this compiles:
> > 
> > writeln("a + b = ", a + b);
> > 
> > But this does not:
> > 
> > writeln(AliasSeq!("a + b = ", a + b));
> > 
> > -Steve
> 
> As Paul Backus brought up in a PR, you can use `std.typecons.tuple`s instead, to use expressions. Example:
> 
> auto foo = tuple(i"a + b = $(a+b)");

There is more than meets the eye here, that I think we should be aware of, whether or not it affects the current prospective DIP.

Firstly, there's the compiler's internal representation that Walter
calls a "tuple" (N.B.: not to be confused with std.typecons.tuple) which
is basically a list of "stuff", where "stuff" can be any of: (1) a basic
type with a compile-time known value; (2) a type; (3) an alias to a
Symbol, where a Symbol can be anything that has an identifier associated
with it (basically, an entry in one of the symbol tables used by the
compiler to keep track of identifiers); (4) a function literal aka
lambda, which in my knowledge has some degree of special treatment,
though for the most part it behaves just like (3).

Secondly, there's std.meta.AliasSeq, which is defined as:

	alias AliasSeq(T...) = T;

The `T...` captures a template argument list, which is a "tuple" in Walter's sense of the word, and gives it an identifier that can be referred to in code (otherwise, there is no way to refer to the compiler internal "tuple").  I had thought that AliasSeq ought to be able to capture all instances of "tuple"s, but apparently I was wrong -- a "tuple" apparently *can* contain an expression, but expressions cannot be captured by AliasSeq because of grammatical / syntactical restrictions placed on template argument lists.  Marler's PR apparently *does* let interpolated strings capture expressions in a way that AliasSeq cannot.

Thirdly, there's std.typecons.Tuple, of which std.typecons.tuple is simply a thin wrapper mainly serving as syntactic sugar for constructing instances of std.typecons.Tuple.  There's a very important difference between std.typecons.Tuple and the compiler internal "tuple" in Walter's sense of the word: std.typecons.Tuple is a *runtime* object that contains a tuple of *values*.  In contrast, the compiler internal "tuple" is (obviously) compile-time only.  It basically behaves like an anonymous struct.  Note that because it is a runtime object, it CANNOT be used with AST stage compile-time constructs like static if, static foreach, template expansions, etc.. If you try to access its values in a static if, you'll get an error. It *is* usable in CTFE, though, if it can be initialized with compile-time known values.

What we need for this DIP is for interpolated strings to be lowered to the first kind of tuple, the compiler-internal "tuple" that can capture AST-accessible "stuff" like string literals and expressions.  I had thought it was equivalent to AliasSeq, but apparently there's a discrepancy, and AliasSeq cannot bind expressions which is a no-go. We cannot use std.typecons.Tuple because it's generally frowned on for the compiler to depend on Phobos (even though the ^^ operator "cheats" in that respect -- but to be fair, that was a historical accident predating the compiler/Phobos clean separation policy). Furthermore, std.typecons.Tuple cannot be used in static if and other AST stage constructs, so that's also a no-go.


T

-- 
I don't trust computers, I've spent too long programming to think that they can get anything right. -- James Miller
December 10, 2018
On Monday, 10 December 2018 at 05:43:48 UTC, H. S. Teoh wrote:
> On Sat, Dec 08, 2018 at 05:17:13PM +0000, o via Digitalmars-d wrote:
>> 
>> As Paul Backus brought up in a PR, you can use `std.typecons.tuple`s instead, to use expressions. Example:
>> 
>> auto foo = tuple(i"a + b = $(a+b)");
>
> There is more than meets the eye here, that I think we should be aware of, whether or not it affects the current prospective DIP.
>
> [...]
>
> What we need for this DIP is for interpolated strings to be lowered to the first kind of tuple, the compiler-internal "tuple" that can capture AST-accessible "stuff" like string literals and expressions.  I had thought it was equivalent to AliasSeq, but apparently there's a discrepancy, and AliasSeq cannot bind expressions which is a no-go. We cannot use std.typecons.Tuple because it's generally frowned on for the compiler to depend on Phobos (even though the ^^ operator "cheats" in that respect -- but to be fair, that was a historical accident predating the compiler/Phobos clean separation policy). Furthermore, std.typecons.Tuple cannot be used in static if and other AST stage constructs, so that's also a no-go.
>
>
> T

To be clear: the proposal is, and has always been (to my knowledge), that interpolated strings should lower to a compile-time sequence, and not a Phobos Tuple.

The point I was making, in the PR "o" mentioned, is that you can pass the compile-time sequence you get from the interpolated string to `std.typecons.tuple` in order to store the values of the expressions in a Phobos Tuple at runtime--as though you had typed:

    auto foo = tuple("a + b = ", a + b);

In other words, it's an example of usage, not part of the core proposal.
December 10, 2018
On Thursday, 6 December 2018 at 00:32:48 UTC, Adam D. Ruppe wrote:
> On Thursday, 6 December 2018 at 00:20:53 UTC, H. S. Teoh wrote:
>> Why can't this be added to to code.dlang.org as a library / dub package / whatever?
>
> Library things cannot access the local scope of the string unless you mixin.
>
> So
>
> mixin(interp!"foo #{a}");
>
> is doable as a library (and I know Nick Sabalusky's scriptlike has it, probably among others), but
>
> string b = "foo #{a}";
>
> is only doable as a language feature.

I have some syntax suggestion...

Interpolated string would fit well with string-mixins. I sometimes tend to use the following pattern:

        enum densityToBitmap(int x, int y, int z) =
            q{
                if (length(%d, %d, %d) <= 0)
                    index |= (1 << cornerIds[%d][%d][%d]);
            }.format(x, y, z, x, y, z);

        mixin(densityToBitmap!(0, 0, 0));
        mixin(densityToBitmap!(0, 0, 1));
        // etc ...

So I use the q{ ... } syntax when the string contains D code to be "mixed-in" later. Using "format" is a bit awkward, so interpolated strings would help to make the code more readable, and we could still keep the braces-syntax.

For example, replacing the "q{ ... }.format(...)" by a "i{ ... }.text"...
December 10, 2018
On Friday, 7 December 2018 at 19:52:41 UTC, o wrote:
> On Friday, 7 December 2018 at 17:11:35 UTC, Atila Neves wrote:
>> Every language change is a cost, and therefore should justify its inclusion. I personally don't think that it is in this case just to make a niche use case slightly easier, and this coming from someone from that niche!
>
> Think about `foreach`, `foreach_reverse`, UFCS, WYSIWYG strings, and `switch`. These are all just so-called "niche cases". When you strip out all of the syntax "niches" from a language, you are more or less left with assembly. Hell, assembly itself is just sugar over pure machine code! So with this attitude, why not ditch D and program in machine language?
>
> It's the same case for string interpolation. It *is* possible to live without it, but it is just damn nice when you have it.
>

Strawman.

My point isn't that syntax sugar isn't needed, is that in this case the problem is easily solved with a library (and has been), and doesn't apply to anything except for multiline code generation, which is a niche.
December 10, 2018
On Thursday, 6 December 2018 at 16:19:12 UTC, Steven Schveighoffer wrote:
> With the concept of lowering to a tuple, I'd love to use such a thing for database queries.
>
> For instance:
>
> db.exec("UPDATE Foo SET a = ?, b = ?, c = ?, d = ? WHERE id = ?", aval, bval, cval, dval, id);
>
> vs.
>
> db.exec(i"UPDATE Foo SET a = $aval, b = $bval, c = $cval, d = $dval WHERE id = $id");

I really like that, but I'd add a caveat: this syntax makes it harder for db.exec to know which arguments you give it are trusted compile-time inputs, and which arguments are unsafe runtime inputs.

I'd argue for a second syntax to be added as well, fi"formatted string". So:

db.exec(fi"UPDATE Foo SET a = $aval, b = $bval, c = $cval, WHERE id = $id");

would lower to:

db.exec("UPDATE Foo SET a = %s, b = %s, c = %s, WHERE id = %s", aval, bval, cval, id);

That way, db.exec would be able to interpret its first argument as trusted input and everything else as unsafe.

That syntax might be redundant if a builtin FromInterpolation struct is created. The thing is, there have been arguments against using a builtin struct, and a db.exec method built for interpolation would be incompatible with regular use, so this:

db.exec("UPDATE Foo SET a = ",aval,", b = ",bval,", c = ",cval,", WHERE id = ",id);

would not work, which would have to be documented, etc.

On the other hand, a fi"some string with $var" syntax could leverage any already existing db.exec method with a "C format" first parameter (including actual C functions?), without forcing the library implementation to differentiate between normal arguments and FromInterpolation arguments.
December 10, 2018
On Monday, 10 December 2018 at 10:55:05 UTC, Atila Neves wrote:

> My point isn't that syntax sugar isn't needed, is that in this case the problem is easily solved with a library (and has been), and doesn't apply to anything except for multiline code generation, which is a niche.

It not quite a niche if you are dealing with sql scripts as part of your job description.

-Alex