December 09, 2021
On Thursday, 9 December 2021 at 14:18:35 UTC, Steven Schveighoffer wrote:
> Granted, the DIP does not discuss this possibility.

For this specific example, the text says the elements are preprocessed with escapeShellCommand, which would be necessary for format() and text(), but not necessarily for the interpolated tuple.

It is more of a syntax comparison than a feature demo. I do think the dip is legitimately weak on actually showing this aspect, even if the facilities are there in the substance.
December 09, 2021

On Thursday, 9 December 2021 at 14:13:58 UTC, Ola Fosheim Grøstad wrote:

>

On Thursday, 9 December 2021 at 14:04:18 UTC, Kagamin wrote:

>

DSLs are already possible with template mixins in a clean form without sigils.

You mean as string mixins?

Just to clarify to avoid unnecessary discussion about what I wrote, as I might not have been specific enough:

I am not suggesting the implementation of builtin string interpolation, but custom literals with conversion functions. It should probably not be called string_interpolation, just convert or @convert.

This is different from string mixins as it would be more composable, overloadable, and with stronger typing and no mixin.

It should work for custom literals like 100.34ms as well as sql"SELECT …".

As such, you would integrate the "DSL" more with regular D-code than you do with string mixins.

Basically: try to find a generic solution for custom literals that allows the implementation of string-interpolation.

December 09, 2021

On Wednesday, 8 December 2021 at 22:10:32 UTC, Steven Schveighoffer wrote:

>

On 12/8/21 4:31 PM, kdevel wrote:
[...]

> >

How is the proper separation of code (query) and data achieved in this case?

Because the sqlExec function figures it out based on the interpolation header. It can tell which parts were literal strings, and which parts were interpolation parameters.

So the string interpolation is used to emulate something like embedded SQL (ESQL) with the exception that the (SQL) code is quoted. ESQL looks like this [1]:

   EXEC SQL INSERT INTO tablename VALUES (:variablename);

This is clearly favorable over embedded question marks plus argument lists.

>

The interpolation parameters are replaced with "?", and then the parameters are passed as data (to avoid SQL injection as expected).

I missed that part.

[...]

>

e.g. (from a real line of code in my codebase):

conn.exec("UPDATE organization SET loc_lat = ?, loc_lon = ? WHERE id = ?", loc_latitude, loc_longitude, id);

// compare to:
conn.exec(i"UPDATE organization SET loc_lat = $loc_latitude, loc_lon = $loc_longitude WHERE id = $id");

Final questions: What happens if the "i" in front of the string is accidentally lost? Compile-time oder runtime error?

How does the compiler/runtime know which type of interpolation to choose? I mean if you have

   conn.exec (i"UPDATE organization SET loc_lat = $loc_latitude...
   html.output (i"<input value=\"$value\" ...

how and where is decided to use the SQL interpolation in the first and the HTML escaping in the second line?

What is the return type of the interpolation?

Stefan

[1] https://en.wikipedia.org/wiki/ECPG#Using_host_variables

PS: The following code snippet is from the YAIDIP document:

   executeShell("wget " ~ url ~ " -O" ~ file ~ ".frag && mv " ~ file ~ ".frag " ~ file);

That should not have been written in the first place. This code is prone to shell injection and the only shell-specific functionality is that of the "&&". Long story short: I would have written it that way:

   execute(["wget", url, "-O", file ~ ".frag"]).status == 0
   &&
   execute(["mv", file ~ ".frag ", file]);
December 09, 2021

On Thursday, 9 December 2021 at 14:25:10 UTC, Steven Schveighoffer wrote:

>

What is that sql function doing? It's not just concatenating strings, and it's also not anything I would ever want to use, in original or interpolation form. It appears to suggest it's going to happily do sql injection as well.

Well, the DIP does not propose string building, it is basically string-splitting with a bit of mixin… (kinda)

Anyway, you could define constants for SELECT, FROM and WHERE and get even better syntax:

sql(SELECT, r[0], r[3], FROM, t[3], WHERE, c[6])

Then let sql escape-wrap the parameters.

>

For this fictitious example, maybe. But I already see huge potential in my real actual libraries that I've written.

Ok, but maybe you could write even better libraries if D added custom literals instead? :-)

>

You don't have to use it if you don't want to.

True, I don't use string interpolation in JavaScript much either. I use it everywhere in Python. The details matters a lot for it to increase readability.

I just wish D would focus more on providing generic solutions than N narrow special cases. I think these special cases are pushed in because people in the forums are too impatient to wait for the emergence of a generic solution. Understandable, but not good for the compiler/language over time.

December 09, 2021

On 12/9/21 9:25 AM, WebFreak001 wrote:

>

Love the idea of having type-safety with this! JS has similar syntax with sql`...` where it will call the function sql with the parts of the interpolated string.

https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Template_literals

This is exactly what the proposal is doing. But instead of using sql as a specialized prefix (you have to be careful with these, as adding arbitrary literal prefixes can mess up the grammar) it's just a parameter tuple, and you specify the function as normal.

i.e. this is practically identical to:

sql(i"SELECT x,y,z FROM $something WHERE $condition");

Or even:

i"SELECT x,y,z FROM $something WHERE $condition".sql;

-Steve

December 09, 2021

On 12/9/21 9:33 AM, kdevel wrote:

>

On Wednesday, 8 December 2021 at 22:10:32 UTC, Steven Schveighoffer wrote:

>

On 12/8/21 4:31 PM, kdevel wrote:
[...]

> >

How is the proper separation of code (query) and data achieved in this case?

Because the sqlExec function figures it out based on the interpolation header. It can tell which parts were literal strings, and which parts were interpolation parameters.

So the string interpolation is used to emulate something like embedded SQL (ESQL) with the exception that the (SQL) code is quoted. ESQL looks like this [1]:

    EXEC SQL INSERT INTO tablename VALUES (:variablename);

This is clearly favorable over embedded question marks plus argument lists.

Yes, this is the biggest point of the DIPs that have been introduced so far -- put the parameters in context.

> >

The interpolation parameters are replaced with "?", and then the parameters are passed as data (to avoid SQL injection as expected).

I missed that part.

It might be implied and not specifically spelled out (I don't know, I read the DIP a long time ago).

>

[...]

>

e.g. (from a real line of code in my codebase):

conn.exec("UPDATE organization SET loc_lat = ?, loc_lon = ? WHERE id = ?", loc_latitude, loc_longitude, id);

// compare to:
conn.exec(i"UPDATE organization SET loc_lat = $loc_latitude, loc_lon = $loc_longitude WHERE id = $id");

Final questions: What happens if the "i" in front of the string is accidentally lost? Compile-time oder runtime error?

It depends. If conn.exec accepts a standard string, then it's a runtime error -- without the i, the string is just a string, which contains the literal data with $loc_latitude, etc. which the SQL server doesn't understand. This is similar to what happens when you do (as I often do): writeln("%s: %s", name, value);

If conn.exec only accepts interpolated literals, then it's a compile time error.

>

How does the compiler/runtime know which type of interpolation to choose? I mean if you have

    conn.exec (i"UPDATE organization SET loc_lat = $loc_latitude...
    html.output (i"<input value=\"$value\" ...

how and where is decided to use the SQL interpolation in the first and the HTML escaping in the second line?

That is the beauty of this proposal! The parameters are simply passed as-is into the function. If the function accepts them properly, it gets to decide how to handle it.

html.output can do whatever it wants differently than conn.exec.

>

What is the return type of the interpolation?

There isn't one. The interpolation is not a function, it's a literal that expands into a parameter list.

>

PS: The following code snippet is from the YAIDIP document:

    executeShell("wget " ~ url ~ " -O" ~ file ~ ".frag && mv " ~ file ~ ".frag " ~ file);

That should not have been written in the first place. This code is prone to shell injection and the only shell-specific functionality is that of the "&&". Long story short: I would have written it that way:

    execute(["wget", url, "-O", file ~ ".frag"]).status == 0
    &&
    execute(["mv", file ~ ".frag ", file]);

Yeah, it might not explicitly state that the original code is subject to injection, but the interpolated version has the potential to avoid it, whereas the original snippet has no chance.

-Steve

December 09, 2021

On Thursday, 9 December 2021 at 14:57:25 UTC, Steven Schveighoffer wrote:

>

(you have to be careful with these, as adding arbitrary literal prefixes can mess up the grammar)

(no)

December 09, 2021

On Thursday, 9 December 2021 at 14:57:25 UTC, Steven Schveighoffer wrote:

>

On 12/9/21 9:25 AM, WebFreak001 wrote:

>

Love the idea of having type-safety with this! JS has similar syntax with sql`...` where it will call the function sql with the parts of the interpolated string.

https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Template_literals

This is exactly what the proposal is doing. But instead of using sql as a specialized prefix (you have to be careful with these, as adding arbitrary literal prefixes can mess up the grammar) it's just a parameter tuple, and you specify the function as normal.

i.e. this is practically identical to:

sql(i"SELECT x,y,z FROM $something WHERE $condition");

Or even:

i"SELECT x,y,z FROM $something WHERE $condition".sql;

-Steve

I think identifiers immediately followed by a string literal are unambiguous. Currently a syntax error, afterwards useful interpolation.

The i"" proposal allows to pass multiple arguments at once, and with that adds new cases to the compiler that a single literal can be multiple arguments. The identifier + string literal stays within bounds of existing behavior.

I think you would really really never want to pass these raw tuple values to any function other than to explicitly designed interpolated string handlers.

Given that assumption I think it's safe to say the i prefix is redundant, and you should just always need to use a handler function. The identifier + string literal syntax elegantly does this without redundant syntax, it's familiar to JS programmers and it doesn't allow passing more than the interpolated string to handler functions or functions with variadic arguments. (which is a good thing)

Samples:

sql(i"SELECT x,y,z FROM $something WHERE $condition")
text(i"hello $name")
mixin(i"class $name {}")

vs

i"SELECT x,y,z FROM $something WHERE $condition".sql
i"hello $name".text
mixin(i"class $name {}") // no equivalent

vs

sql"SELECT x,y,z FROM $something WHERE $condition"
text"hello $name"
mixin"class $name {}"

or have some kind of new function call punctuation:

sql$"SELECT x,y,z FROM $something WHERE $condition"
text$"hello $name"
mixin$"class $name {}"

and if you want to actually access the tuple for variadic template arguments (including the header) you could still do this:

AliasSeq"hello $name"

(or alias I = AliasSeq; and I"hello $name")

December 09, 2021

On Thursday, 9 December 2021 at 15:16:40 UTC, WebFreak001 wrote:

>

On Thursday, 9 December 2021 at 14:57:25 UTC, Steven Schveighoffer wrote:

>

[...]

i.e. this is practically identical to:

sql(i"SELECT x,y,z FROM $something WHERE $condition");

Or even:

i"SELECT x,y,z FROM $something WHERE $condition".sql;

-Steve

[...]

and I want to add, this is the super rare case:

foo(i"hello $name")

this is the much more common case:

foo(i"hello $name".text)
// or
foo(text(i"hello $name"))

I don't think the common case should always have this extra i prefix + needed function calling parentheses or ufcs dot. Just only writing text"hello $name" is shorter, easier to type, better to read.

December 09, 2021

On Thursday, 9 December 2021 at 15:16:40 UTC, WebFreak001 wrote:

>

[...]

and if you want to actually access the tuple for variadic template arguments (including the header) you could still do this:

AliasSeq"hello $name"

(or alias I = AliasSeq; and I"hello $name")

this should have been:

tuple"hello $name"
// or
alias I = tuple;
I"hello $name"