New blog post on the cost of compile time

Steven Schveighoffer schveiguy at gmail.com
Sat Feb 18 17:16:18 UTC 2023


On 2/18/23 7:04 AM, Nick Treleaven wrote:
> On Monday, 16 January 2023 at 15:13:04 UTC, Steven Schveighoffer wrote:
>> In general, Phobos templates should try to avoid using simple wrappers 
>> for internal things. One thing I didn't discuss in the post is that 
>> the `ReturnType` instances here are only ever going to be instantiated 
>> *once*, and on something that is *never used* (the lambda function).
> 
> If each test used `lvalueOf` from std.traits then the instantiations 
> would be reused (there would be 2 just in isInputRange), and likely 
> elsewhere too. There could be a convention to use lvalueOf too and avoid 
> instantiating rvalueOf for instantiation reuse.
> 
> ```d
> is(typeof(() { return (*cast(R*)null).empty; }()) == bool)
> is(typeof(() { return lvalueOf!R.empty; }()) == bool)
> ```
> 
> That looks a bit nicer as it says what its intent is. Hopefully it 
> wouldn't affect memory/performance much.
> 
> Another idea is to factor out all the `r` parameter declarations into 
> one, and use that for the return type tests too:
> 
> ```d
> // now
> enum isInputRange(R) =
>      is(typeof(R.init) == R)
>      && is(typeof(() { return (*cast(R*)null).empty; }()) == bool)
>      && (is(typeof((return ref R r) => r.front)) ||
>          is(typeof(ref (return ref R r) => r.front)))
>      && !is(typeof(() { return (*cast(R*)null).front; }()) == void)
>      && is(typeof((R r) => r.popFront));
> 
> // factored
> enum isInputRange(R) =
>      __traits(compiles, (R r) {
>          static assert(
>              is(typeof(R.init) == R) &&
>              is(typeof({ return r.empty; }()) == bool) &&
>              is(typeof(() return => r.front)) &&
>              is(typeof(ref () return => r.front)) &&
>              !is(typeof({ return r.front; }()) == void) &&
>              is(typeof({ r.popFront; }))
>          );
>      });
> ```
> The factored version looks much easier to read for me. I don't know how 
> they compare for memory/performance though.

This is how isInputRange used to look. The reason it was changed is 
because the compiler now "sees" the different clauses separated by &&, 
and will tell you which one failed. When you wrap it like this, it just 
sees one big constraint.

I actually did get a PR merged. It wasn't as simple as I had written in 
that blog post, due to the stupid `inout` requirement that `inout` data 
can only be used inside a function with an `inout` parameter.

I did start with using `lvalueOf!R`, but then realized that since 
`isInputRange` validates that `typeof(R.init) == R`, I just used 
`R.init` as the parameter.

See the merged PR here: https://github.com/dlang/phobos/pull/8682

-Steve


More information about the Digitalmars-d mailing list