Jump to page: 1 24  
Page
Thread overview
String Interpolation Compare - DIP1027 and YAIDIP
Oct 21, 2023
Walter Bright
Oct 21, 2023
monkyyy
Oct 21, 2023
bachmeier
Oct 21, 2023
Adam D Ruppe
Oct 21, 2023
Walter Bright
Oct 21, 2023
Walter Bright
Oct 21, 2023
Walter Bright
Oct 21, 2023
jmh530
Oct 21, 2023
Walter Bright
Oct 21, 2023
Paolo Invernizzi
Oct 21, 2023
Imperatorn
Oct 21, 2023
Walter Bright
Oct 21, 2023
Walter Bright
Oct 21, 2023
Walter Bright
Oct 21, 2023
Walter Bright
Oct 21, 2023
Walter Bright
Oct 21, 2023
Imperatorn
Oct 21, 2023
Paul Backus
Oct 21, 2023
Imperatorn
Oct 21, 2023
Andrea Fontana
Oct 21, 2023
Hipreme
Oct 21, 2023
Alexandru Ermicioi
Oct 21, 2023
Imperatorn
Oct 21, 2023
Alexandru Ermicioi
Oct 21, 2023
Dadoum
October 20, 2023
https://github.com/dlang/DIPs/blob/master/DIPs/rejected/DIP1027.md

https://github.com/John-Colvin/YAIDIP

Both designs fulfill their basic function of string interpolation, and both are user extensible to enable most anything. They look rather alike. Beyond that, they are quite different. DIP1027 is based around the printf()/writef()/format() model, while YAIDIP is based on the write() model. DIP1027 generates a format string followed by arguments to it, YAIDIP generates a template instance followed by a sequence of string arguments.

The rest is about differences that matter. Of course I'm biased about this - I went looking for fault and found it. It's better to find fault in advance rather than belatedly, because whatever we pick we're going to be stuck with. I strongly favor designs that are self-evident and require minimal to no documentation. I prefer designs that are simple building blocks, where the user can combine such blocks to form more complex designs. Designs that have minimal special cases and fit with the rest of the language are better.

As with Ddoc and unittest, designs that don't address every need, but cover the vast bulk of needs with a simple self-evident design, are better designs.

I apologize for any typos and mistakes due to misunderstanding YAIDIP.

# YAIDIP

## Pros

1. Is less susceptible (but not immune) to accidentally matching the wrong function or template.

## Cons

1. It's inefficient because of more than double the number of arguments that have to be passed.

2. It's inefficient because it requires the arguments to be converted to string temporaries, and then the strings are appended to the result. This is both slow, and requires string memory allocations. In contrast, a formatter (like printf and writef) does not require string intermediates, the generated characters can be sent directly to the sink.

3. To get anything other than the default conversion, such as adding leading spaces, writing a formatting conversion function is necessary, and then called. This means the i-string is going to get quite long. Consider the difference between:

```
    i"axy:  ${%03d}a ${%e}x ${%20.10f}y"  // DIP1027
```
```
    i"axy:  $leadingZero$digits(3)$a $scientific$x $fixed(20,10)$y" // YAIDIP
```

If there are more than a small number of embedded arguments, the length of the i-string becomes untenable and unreadable. The compact formatting language, which has been pretty standard for nearly 50 years, is a lot easier to deal with.

4. If the manipulators are not in scope, there's no way to qualify them with the '.' syntax. Temporary aliases are necessary:

```
    alias leadingZero = std.istring.leadingZero;
    alias digits = std.istring.digits;
    alias scientific = std.istring.scientific;
    alias fixed = std.istring.fixed;
    i"axy:  $leadingZero$digits(3)$a $scientific$x $fixed(20,10)$y"
```

5. The tuple output, which the user is sooner or later going to be confronted with, looks like (copied from YAIDIP):

```
    writeln(.object.imported!"core.interpolation".InterpolationHeader!("", "x", " can be written as ", scientific, "", x, " or ", fixed(20, 10), "", x, ".")(),
  x, " can be written as ", scientific, "", x, " or ", fixed(20, 10), "", x, ".");
```

This will show up in error messages, and the user is confronted with how the sausage is made. I had to read YAIDIP several times to try to figure out what that text actually meant. Contrast that with:

```
    writefln("%s can be written as %e or %20.10f", x, y);
```

where it is simple and self-evident what is happening.

6. It requires another template added to object.d, which is already so bloated with templates it consumes a large compile time penalty. It requires the user to understand this template.

7. It requires the creation of another module, call it `std.istring`, to contain all the manipulators a user will expect to see (such as `scientific`).

8. There will be difficulties using this with betterC because of the required string allocations mentioned earlier.

9. i-strings are special case behaviors for pragma, mixin, assert, static assert, function calls, constructor calls, and template instantiations. They are not general purpose. They cannot be used for things like generating tuples for other uses.

----------------------------------------------

# DIP1027

# Pros

1. does not require memory allocation

2. does not require object.d support

3. does not require a library of manipulators

4. works out of the box with all the existing formatted string functions, and leverages the decades of optimizations that the C formatted string functions employ, along with existing knowledge of those functions and how they work

5. can do everything YAIDIP does

6. is faster

7. uses less memory

8. does not emit template bloat into the object files

9. does not emit structs into the object files

10. the i-strings are much more compact

11. generates a tuple that is self-evident

12. generates a tuple that can be used anywhere tuples work

# Cons

1. Is more susceptible to inadvertent matching with the wrong function, because the tuples generated are tuples of strings, integers, and other ordinary types.

-----------------------------

Nothing is perfect, but DIP1027 is a much better fit for D's style of simple elegance.
October 21, 2023
On Saturday, 21 October 2023 at 01:50:33 UTC, Walter Bright wrote:
> 
airnt both implimented?
even if you hate it, can you just throw one of them behind a compiler flag and mark it as "not final"?


October 21, 2023
On Saturday, 21 October 2023 at 02:10:06 UTC, monkyyy wrote:
> On Saturday, 21 October 2023 at 01:50:33 UTC, Walter Bright wrote:
>> 
> airnt both implimented?
> even if you hate it, can you just throw one of them behind a compiler flag and mark it as "not final"?

Given that I'm not able to follow the details of either proposal (after the first 50 pages I fall asleep) I think it would be helpful to try both with an experimental flag. My impression is that many of the arguments in favor of one proposal or another are speculative.
October 21, 2023
Note to readers: you don't have to believe second-hand nonsense. There's functional implementations to play with already:

YAIDIP's first draft itself: https://github.com/dlang/dmd/pull/15714

YAIDIP is not perfect, so I made a better iteration on the concept too:
https://github.com/dlang/dmd/pull/15715

Some things in there could still be changed, of course, but even in its current draft state, you can easily see what is true and false in these comparisons.




On Saturday, 21 October 2023 at 01:50:33 UTC, Walter Bright wrote:
> YAIDIP generates a template instance followed by a sequence of string arguments.

Not true. The only string arguments are the strings interpolated with the arguments.

> 2. It's inefficient because it requires the arguments to be converted to string temporaries, and then the strings are appended to the result.

Not true. You have shown zero understanding of what it is, even though there's an implementation you could look at in addition to the document!

>     i"axy:  $leadingZero$digits(3)$a $scientific$x $fixed(20,10)$y" // YAIDIP

This is one possible use case of it, but there's several others, including using format strings. It is 100% up to the library what to do; the compiler is agnostic to these specifics.

> 4. If the manipulators are not in scope, there's no way to qualify them with the '.' syntax. Temporary aliases are necessary:

Not true. This might be the stupidest of your ignorant statements, since even basic knowledge of how D modules work show your examples are nonsense (you can `import std.istring;`!), and if you read the DIP or played with the implementation, you'd also know you can enclose a fully-qualified name in parenthesis too.

> 5. The tuple output, which the user is sooner or later going to be confronted with, looks like (copied from YAIDIP):

This is half true. We could make the compiler error messages nicer with a bit of implementation effort, but currently they messages do indeed look like:

test.d(51): Error: function `test.foos(string s)` is not callable using argument types `(InterpolationHeader, InterpolatedLiteral!"Hello, ", InterpolatedExpression!"name", string, InterpolatedLiteral!"", InterpolationFooter)`
test.d(51):        cannot pass argument `InterpolationHeader()` of type `InterpolationHeader` to parameter `string s`


>     writefln("%s can be written as %e or %20.10f", x, y);

But this is still a dishonest comparison. If you passed that to a `void foos(string s)` you'd get an error message along the lines of:

test.d(52): Error: function `test.foos(string s)` is not callable using argument types `(string, string)` test.d(52):        expected 1 argument(s), not 2

Which would still require the user to understand how the thing works, since if they are thinking they ARE passing a string, they'd wonder why the compiler thinks there's two.

> 6. It requires another template added to object.d, which is already so bloated with templates it consumes a large compile time penalty. It requires the user to understand this template.

Not true.

> 7. It requires the creation of another module, call it `std.istring`, to contain all the manipulators a user will expect to see (such as `scientific`).

Not true. (But this is an option, but it is not a requirement).

> 8. There will be difficulties using this with betterC because of the required string allocations mentioned earlier.

Not true.

> 9. i-strings are special case behaviors for pragma, mixin, assert, static assert, function calls, constructor calls, and template instantiations. They are not general purpose. They cannot be used for things like generating tuples for other uses.

Half true, they would be special case for pragma, etc., if you wanted to (I don't btw, I'd tell the user to call the function), but they *can* be used for other users. THAT'S THE WHOLE POINT.

> # DIP1027
>
> # Pros
>
> 3. does not require a library of manipulators

Not true - that library is `format` or `printf` etc., but it is there.

Of course, the other proposal also works with those functions. We even provided implementations - it is a short function. One short example is here: https://github.com/dlang/dmd/pull/15715#issuecomment-1773146760

> 5. can do everything YAIDIP does

Completely and utterly false, as we've gone over many, many, many times.

> 10. the i-strings are much more compact

False.

> 11. generates a tuple that is self-evident

That's just like, your opinion, man.

> 12. generates a tuple that can be used anywhere tuples work

False.

> # CONS

> 1. Is more susceptible to inadvertent matching with the wrong function, because the tuples generated are tuples of strings, integers, and other ordinary types.

Hey, you finally said something that's 100% true!


Again, to see the truth, look at the implementations:

YAIDIP itself: https://github.com/dlang/dmd/pull/15714

And a better iteration of the concept:
https://github.com/dlang/dmd/pull/15715

DIP texts are hard to read. Experimenting with it is easy. Don't believe second-hand nonsense.
October 20, 2023
The examples I used are copied verbatim from the YAIDIP. If they're all false, please write a better proposal.
October 21, 2023

On Saturday, 21 October 2023 at 02:22:49 UTC, Adam D Ruppe wrote:

>

On Saturday, 21 October 2023 at 01:50:33 UTC, Walter Bright wrote:

>
  1. It's inefficient because it requires the arguments to be converted to string temporaries, and then the strings are appended to the result.

Not true. You have shown zero understanding of what it is, even though there's an implementation you could look at in addition to the document!

You can even call printf with betterC (no runtime memory allocation whatsoever, not even malloc) with introspection of parameters, something that 1027 cannot do.

> >
i"axy:  $leadingZero$digits(3)$a $scientific$x $fixed(20,10)$y" // YAIDIP

This is one possible use case of it, but there's several others, including using format strings. It is 100% up to the library what to do; the compiler is agnostic to these specifics.

YAIDIP:

i"axy:  $a{03} $x{e} $y{20.10}"

Compare that to dip 1027 (how verbose!)

i"axy:  ${%03d}a ${%e}x ${%20.10f}y"
> >
  1. The tuple output, which the user is sooner or later going to be confronted with, looks like (copied from YAIDIP):

This is half true. We could make the compiler error messages nicer with a bit of implementation effort, but currently they messages do indeed look like:

test.d(51): Error: function `test.foos(string s)` is not callable using argument types `(InterpolationHeader, InterpolatedLiteral!"Hello, ", InterpolatedExpression!"name", string, InterpolatedLiteral!"", InterpolationFooter)`
test.d(51):        cannot pass argument `InterpolationHeader()` of type `InterpolationHeader` to parameter `string s`

YAIDIP is here to help!

Perhaps use `std.conv.text` to make a string from an interpolation tuple?

And of course we can clean up the parameter types to be more readable (we already do this for string).

> >
  1. There will be difficulties using this with betterC because of the required string allocations mentioned earlier.

How can you possibly think that YAIDIP requires allocations? The only proposal that requires allocations is DIP1027, since you must rebuild the format string if your function doesn't support printf style format specifiers (i.e. mysql). You have it exactly backwards.

> >

DIP1027

Pros

  1. does not require a library of manipulators

Not true - that library is format or printf etc., but it is there.

Not even printf works as expected, only writef.

Try doing printf with a string parameter (not a string literal) with DIP1027.


I want to stress that I'm not in love with YAIDIP. If we want to go with a templated interpolation tuple, I'd wish for 1036, but without the auto-string conversion.

-Steve

October 21, 2023

On Saturday, 21 October 2023 at 03:48:49 UTC, Walter Bright wrote:

>

The examples I used are copied verbatim from the YAIDIP. If they're all false, please write a better proposal.

Your interpretation is false, not the examples.

They are examples of what's possible, not requirements.

That being said, the proposal needs much work. To be fair it's not an official proposal. It should be made clear enough to be understood by the language maintainers.

-Steve

October 20, 2023
On 10/20/2023 8:51 PM, Steven Schveighoffer wrote:
> YAIDIP:
> 
> ```d
> i"axy:  $a{03} $x{e} $y{20.10}"
> ```

You and I must be reading a different version of https://github.com/John-Colvin/YAIDIP

May I quote:

"There is no need for defining, implementing, and memorizing a sui generis mini-language of encoded format specifiers --- all formatting can be done with D language expressions. Continuing the example, the library can just as easily define parameterized formatting for floating-point numbers, such as width, precision, and scientific notation:"

```
void fun(double x) {
    writeln(i"$x can be written as $scientific$x or $(fixed(20, 10))$x.");
    // Lowering: --->
    // writeln(.object.imported!"core.interpolation".InterpolationHeader!("", "x", " can be written as ", scientific, "", x, " or ", fixed(20, 10), "", x, ".")(),
    //     x, " can be written as ", scientific, "", x, " or ", fixed(20, 10), "", x, ".");
}
```
October 20, 2023
On 10/20/2023 8:51 PM, Steven Schveighoffer wrote:
> Not even printf works as expected, only writef.
> 
> Try doing printf with a string parameter (not a string literal) with DIP1027.

To use printf with i-strings, it's implicitly necessary to use arguments that are compatible with printf. That means const(char)* arguments, not string arguments. This is something that should be obvious once how i-string conversion to tuples works.

DIP1027 has zero knowledge of `writef` or `printf` or `format`.

--- However ---

Ever since we added printf format checking to the language, I've toyed with the idea of going a step further and adjusting the arguments (and formats) of the calls to printf to make them work.

For example, a D string argument `s` would be split into two parameters, `cast(int)s.length, s.ptr`. The format `%s` would be replaced with `%.*s`. In other words, you could do things like:

```
printf("integer %s", 67);
```

would be rewritten as:

```
printf("integer %d", 67);
```

After all, if the format checker can give an error message with the correct format specifier, why not just fix it?

However, this would be independent of string interpolation. It's just that the two separate initiatives would fit together handsomely when dealing with printf.

October 20, 2023
On 10/20/2023 8:51 PM, Steven Schveighoffer wrote:
> How can you possibly think that YAIDIP requires allocations?

How else can you make a user-defined dec() work?


> The only proposal that requires allocations is DIP1027, since you must rebuild the format string if your function doesn't support printf style format specifiers (i.e. mysql). 

The example I gave in the other thread shows how to not need to rewrite the format string.

https://www.digitalmars.com/d/archives/digitalmars/D/Just_another_example_of_missing_string_interpolation_370542.html#N370696

But even if you did rewrite it, it doesn't escape the template function, and can be RAII'd.

Dealing with a string allocated and returned by `dec()` is significantly harder.
« First   ‹ Prev
1 2 3 4