Tuples, CTFE, and Sliding Template Arguments

Paul Backus snarwin at gmail.com
Mon Jan 15 11:22:50 UTC 2024


On Monday, 15 January 2024 at 01:27:00 UTC, Walter Bright wrote:
> 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).
[...]
> 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.

This part of the post is an argument about *usage* complexity, so 
let's compare what 1027 and 1036 are like to use.

For DIP 1027:

* writef just works
* For anything else, you have to process a format string at 
runtime using string parsing.

For DIP 1036:

* writeln just works
* For anything else, you have to process an argument list at 
compile time using introspection.

In the "just works" case, both are equally easy to use.

What about the case where it doesn't "just work"? For DIP 1036, D 
has world-class introspection facilities built into the language 
and standard library. For DIP 1027, the facilities we have for 
string parsing are...regex, I guess? So I would say 1036 has an 
edge here.

> 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.

This part is an argument about *implementation* complexity, so 
let's compare implementations.

DIP 1036's PR includes a lot more tests and documentation than 
DIP 1027's, so comparing the PRs in their entirety doesn't make 
sense. Instead, I'm going to focus on the specific modules in the 
DMD frontend where the "meat" of the implementation lives.

For DIP 1027 [1], we have

* +141 lines in dmd.expressionsem
* +11 lines in dmd.lexer
* +11 lines in dmd.tokens (discounting the unrelated comment)

...which totals to 163 lines.

For DIP 1036 [2], we have

* +78 lines in dmd.expressionsem
* +166 lines in dmd.lexer
* +33 lines in dmd.tokens

...which totals to 277 lines.

So, by this measure, DIP 1036 has a more complex implementation 
than DIP 1027. Although in absolute terms, neither is especially 
complex.

For comparison, if I apply the same methodology to DIP 1038 
(@mustuse) [3], I count 260 lines (in the dsymbolsem, 
expressionsem, statementsem, and mustuse modules)--pretty close 
to DIP 1036. Perhaps I'm flattering myself, but I would consider 
@mustuse to be a feature with a fairly simple implementation.

[1] https://github.com/dlang/dmd/pull/15722/files
[2] https://github.com/dlang/dmd/pull/15715/files
[3] https://github.com/dlang/dmd/pull/13589/files


More information about the Digitalmars-d mailing list