On Thursday, 27 February 2020 at 09:30:30 UTC, Walter Bright wrote:
On 2/27/2020 12:27 AM, Petar Kirov [ZombineDev] wrote:
I'm well aware that allocation is inevitable if we want this behavior. My argument is that this behavior is so ubiquitous that not following it would be surprising to much more people, than if D didn't follow C's Usual Arithmetic Conversions rules. For example, Rust not following those conversion rules is considered a good thing,

Rust does not follow C syntax at all, so nobody will reasonably expect it to have C semantics. D does follow it, it's a feature, so people will have expectations.

I'm not sure where exactly you draw the line, but I would say that C# follows C's syntax about as much as D does. Yet it doesn't import some of the broken C semantics like implicit narrowing conversions (luckily, neither does D) and allowing mixed sign comparisons (the oldest open D issue :( [0]).

My point is that if D didn't follow the usual arithmetic conversions, much fewer newcomers would even notice compared to extremely large backlash that we may get if go with the string interpolation -> raw tuple approach.

[0]: https://issues.dlang.org/show_bug.cgi?id=259

while if D decided to be different than all other languages w.r.t. string interpolation,

You can make it behave like all those other languages simply with:

    f(format("hello $a"));

and there it is. But having it generate a GC allocated string is not so easy to unwind, i.e. it'll be useless with printf and generate unacceptable garbage with writefln. The extra string will always make it slow. Essentially, it'll be crippled. Making D behave like a scripting language will yield scripting performance.

I know, I know. Though I think you misunderstood. There several ways to make printf work with zero allocations. For example:

1. Have a simple pragma(inline, true) wrapper function that will convert the distinct type to printf-style args. This wrapper function can even be named printf as it would work by virtue of function overloading. This is O(1) additional code that once written no one will need to bother with.

2. Have the new type implicitly convert to printf-style args. I think this is what Adam is proposing. While nice to have, I don't think it's necessary.

As for std.stdio.write(f)(ln), there's no reason why any garbage would need to be created, as again, a simple overload that accepts the distinct type will be able to handle it just like it would (performance-wise) with DIP1027. However, with DIP1027, only writef and writefln can be used, while write and writeln will produce wrong results (wrong according to people that have used string interpolation in other languages).

D is a language built up from simple, orthogonal parts (or at least that is a goal). A language built from larger indivisible parts is much, much less user-adaptable.

I appreciate the sentiment. Having orthogonal features in D is important to me as well. However, I think DIP1027 falls short here because it produces a single format string and that way loses all of the structure. This is ok for printf, but not for third-party libraries and even our own std.format, as with a distinct type we won't need to parse the whole format string at all, just the individual format specifiers. In other words, a distinct type would make nothrow std.format a much more tractable problem (at least for some cases).

An example of this is the built-in associative array, which has a series of fairly intractable problems as a result. Another example is the built-in complex type in D, which turned out to be a bad idea - a much better one is
building it as a library type.

AFAIR, most of the problems with D's built-in AAs are that they have an extern (C) interface that relies on typeinfo. If they are fully converted to templated library types, the situation would be much better. IIRC, one of the blocking issues was that D didn't have autovivification [1] operators, so a library type wouldn't be a complete replacement without additional help from the compiler.

So in conclusion, having a distinct library-defined type (in druntime) seems the best way to go to me, as it's more flexible than raw tuples, could allow easy GC-backed conversion to string for script-like code and would offer a superset of the functionality that DIP1027 would offer, while still allowing easy (although not 100% direct) calls to printf.

[1]: https://en.wikipedia.org/wiki/Autovivification

Reply via email to