Walter Bright
| I'll summarize up front, and so one can skip the detailed reply below. It's obvious there's no meeting of the minds here. I'll just explain where I'm coming from.
Features doing simple things should be simple. That's the case with 1027. Doing complicated things should be expected to be more complicated to use. With 1036, it starts out at the other end. It's complicated, with complexity that one has to write additional code to make it simple again (the "filter out the unnecessary templates" thing we talked about).
It's fine that transmorgrifying the string to adapt it to SQL has complexities to it. That's expected. If that's all string interpolation would be used for, that's ok.
But people want to use string interpolation for mixins, etc., all that have nothing to do with SQL. The transmorgrification should not be necessary for those cases, it should just work. But it doesn't, if the filter isn't applied there's a significant runtime and code space cost.
Simple things should be simple, complicated things should expect complexity. But 1036 has simple things being complicated. Doing SQL is about the same level of complexity for 1027 as 1036. For doing simple things, 1036 remains complicated, and 1027 gets simple.
That's the extent of my unease with it.
Does 1027 do *everything* 1036 does? No. There's the Format can be implicitly converted to a string thing. So there's a tradeoff. Do we trade off a minor thing for a fair amount of complexity that yes, the user will see? Every feature in D is a compromise of one sort or another. I fall on one side of that, you the other.
Another illustration of this idea. For algorithmic code, I invented opApply(). But after experience with it, I slowly grew to dislike it because I could never remember how it worked, and would have to reread the documentation on it. The implementation of it is also ugly, as it has to rewrite the code that surrounds it. Heaven help anyone who has to read the code gen output of that. I much prefer the later approach using lambdas. They're simple, easy to remember and use. There isn't much implementation for them; they grew naturally out of other features in the language.
The one thing that lambdas don't do that opApply does is recursion. Some klunky code has to be written to make a lambda do recursion. But that's ok, as there are relatively few needs for recursion, so the simple cases with lambdas are simple, and the complicated cases are more work. This is as it should be.
Nothing comes for free, everything is a compromise.
----------------------------
On 1/13/2024 9:12 AM, Steven Schveighoffer wrote:
> This doesn't help, as an enum implicitly converts to its base type.
It's a point for 1036.
> In none of the proposals I have written or supported, has it been meant for `writef`. I don't understand the desire to hook `writef` and `format`.
A format string is needed to support formats like "%03d". I understand that is not needed for SQL, but support for formats is not so straightforward with 1036.
> Me too. But shouldn't we prefer compiler errors? Shouldn't we use the type system for what it is intended?
We should prefer compiler errors, I agree. But everything has a cost to it.
> I've literally left bugs like this in code for years without noticing until the actual thing (an exception) was printed, and then it was hours to figure out what was happening.
When I've had an exception printed, I'll grep the code base for the message to see where it came from. The message should also say what was wrong. If it's a generic exception, I'll use the debugger to find where it came from. I doubt a format string error would be hard to track down, as it's only one level below the cause of the error.
> This would be a step up, but still doesn't fix the format specifier problem.
I'm not seeing a format specifier problem. %s, ?1, what's the difference? What if the string literals generated by 1036 have a stray ?1 in them? If there's a check for that, I missed it.
> Without a trailer, this isn't solvable technically.
It can by counting arguments and the %s.
> I just meant that it isn't a requirement to disallow them somehow.
I did mention a way it can work.
> The SQL example *DOES NOT* generate a format string, I've told you this multiple times. It generates a string with placeholders. There is no formatting. In fact, the C function doesn't even accept the parameters, those happen later after you generate the prepared statement.
CTFE work is required to generate both "hello ?1 ?2" and "hello %s %s". I understand your point that the latter requires an unacceptable level of CTFE processing, though I don't agree with the "unacceptable" part. I don't see how 1036 is going to deal with stray ? in the string literals without CTFE.
> Things other than SQL *do not require building a string*.
Building a format string enables formats other than %s. For example, %03d. Adam wrote a library function for that, https://github.com/adamdruppe/interpolation-examples/blob/master/lib/format.d which does a lot of CTFE. Noted in it is "the format string is built at compile time".
>> I suspect you routinely use CTFE for far, far more complex tasks. This is a
>> rounding error.
> Wait, so generating an extra template is a bridge too far, but parsing a DSL at compile time is a rounding error?
It's ((number of args) - 1)*2+3 templates. Looking at the object file, they are templates with pretty long names, along with their struct instantiations, which is not free in compiler time or memory consumption.
> Not to mention that concatenation is easy. I can do it in one line (if I don't really care about performance). The same cannot be said for parsing.
As you mentioned before, the code only has to be written once!
|