digitalmars.D - New blog post on the cost of compile time
- Steven Schveighoffer (6/7) Jan 15 2023 Well, I finally got around to it:
- Arjan (4/6) Jan 16 2023 I think it is marveleous. Wondering are there any down sides to
- Steven Schveighoffer (15/22) Jan 16 2023 In this instance, no. This was just a case of "oh, look, there's
- Nick Treleaven (39/44) Feb 18 2023 If each test used `lvalueOf` from std.traits then the
- Steven Schveighoffer (13/60) Feb 18 2023 This is how isInputRange used to look. The reason it was changed is
- Nick Treleaven (39/50) Feb 18 2023 Makes sense, although I don't get that on my machine with dmd
- Paul Backus (6/11) Feb 18 2023 There is at least one project in the project tester that uses
- ryuukk_ (6/20) Feb 18 2023 min, max? why??? i hope that won't happen anytime soon
- Steven Schveighoffer (41/92) Feb 19 2023 uhh... I think I am wrong on the reasoning then. I thought it would keep...
- Nick Treleaven (18/55) Feb 19 2023 OK, it could be implemented. Perhaps with complex failing
- FeepingCreature (15/25) Jan 16 2023 Looks like :handwaves: given a 2.4Ghz processor, that'd be 150k
- max haughton (17/48) Jan 16 2023 Processors these days are both faster than that and have pretty
- Steven Schveighoffer (11/37) Jan 16 2023 Absolutely, I welcome any improvements that bring the current phobos
- Hipreme (6/16) Jan 16 2023 Pretty interesting this post!
- H. S. Teoh (36/37) Jan 17 2023 [...]
- Walter Bright (21/26) Jan 18 2023 https://dlang.org/spec/expression.html#is_expression
- Steven Schveighoffer (37/74) Jan 19 2023 I didn't think of making ReturnType simplified (we know in this case the...
- Commander Zot (7/13) Jan 19 2023 i disagree with this.
- Steven Schveighoffer (4/16) Jan 19 2023 I'm not sure I understand your disagreement with the quote.
- Commander Zot (10/29) Jan 19 2023 maybe i misunderstand your point, but let me express my thoughts
- Steven Schveighoffer (13/36) Jan 19 2023 Yes, this is what I said "less than ideal to have to worry about the
In this post: https://forum.dlang.org/post/tm3p0p$2js2$1 digitalmars.com I mentioned:I did a test on something I was working on for my talk, and I'm going to write a blog post about it, because I'm kind of stunned at the results.Well, I finally got around to it: https://www.schveiguy.com/blog/2023/01/the-cost-of-compile-time-in-d/ Let me know what you think. -Steve
Jan 15 2023
On Monday, 16 January 2023 at 04:30:25 UTC, Steven Schveighoffer wrote:https://www.schveiguy.com/blog/2023/01/the-cost-of-compile-time-in-d/ Let me know what you think.I think it is marveleous. Wondering are there any down sides to using typeof?
Jan 16 2023
On 1/16/23 3:10 AM, Arjan wrote:On Monday, 16 January 2023 at 04:30:25 UTC, Steven Schveighoffer wrote:In this instance, no. This was just a case of "oh, look, there's ReturnType, so I can just use that" instead of trying to actively avoid using the tools in std.traits. But in general, we still want to be able to use the cool tools that Phobos gives us without too much penalty, so the larger problem still remains -- templates just should be better performing. 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). Once the boolean for `isInputRange` is decided, there is no reason to keep that stuff around. Some way to cull those templates from the cache would be most welcome. -Stevehttps://www.schveiguy.com/blog/2023/01/the-cost-of-compile-time-in-d/ Let me know what you think.I think it is marveleous. Wondering are there any down sides to using typeof?
Jan 16 2023
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.
Feb 18 2023
On 2/18/23 7:04 AM, Nick Treleaven wrote:On Monday, 16 January 2023 at 15:13:04 UTC, Steven Schveighoffer wrote: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 -SteveIn 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.
Feb 18 2023
On Saturday, 18 February 2023 at 17:16:18 UTC, Steven Schveighoffer wrote: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.Makes sense, although I don't get that on my machine with dmd v2.101.0: ```d import std.range; int f(R)() if (isInputRange!R) => 2; int i = f!int; ``` ``` isinputrange.d(68): Error: template instance `isinputrange.f!int` does not match template declaration `f(R)()` with `R = int` must satisfy the following constraint: ` isInputRange!R` ``` That's it, nothing about why isInputRange failed. Maybe I'm doing something wrong. Anyway, assuming dmd can use that I wonder if this would work (aside from the inout issue): ```d template isInputRange(R) { extern R r; // dummy enum isInputRange = 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; })); } ``` dmd could still see through the eponymous template to the expression, in theory.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.OK, so `typeof((R r) { return r.empty; } (R.init))` works with inout. Thanks for the blog post BTW.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.Is that validation to detect types with redefined `init`? I didn't realize Phobos needs to care about that.
Feb 18 2023
On Saturday, 18 February 2023 at 19:25:01 UTC, Nick Treleaven wrote:There is at least one project in the project tester that uses redefined `init`, so yes, Phobos has to care about it (at least until the deprecation [1] goes through). [1] https://github.com/dlang/dmd/pull/12512I 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.Is that validation to detect types with redefined `init`? I didn't realize Phobos needs to care about that.
Feb 18 2023
On Saturday, 18 February 2023 at 20:04:27 UTC, Paul Backus wrote:On Saturday, 18 February 2023 at 19:25:01 UTC, Nick Treleaven wrote:There is at least one project in the project tester that uses redefined `init`, so yes, Phobos has to care about it (at least until the deprecation [1] goes through). [1] https://github.com/dlang/dmd/pull/12512I 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.Is that validation to detect types with redefined `init`? I didn't realize Phobos needs to care about that.Declaring tupleof, stringof, min, max and maybe others as members should also be deprecated in the future.min, max? why??? i hope that won't happen anytime soon init/deinit can't be used create/destroy can't be used Maybe it's time to introduce something, a token for builtin features?
Feb 18 2023
On 2/18/23 2:25 PM, Nick Treleaven wrote:On Saturday, 18 February 2023 at 17:16:18 UTC, Steven Schveighoffer wrote:uhh... I think I am wrong on the reasoning then. I thought it would keep going down into the constraint, but it doesn't? Maybe it was planned? I do know that && in the constraint itself does do that. e.g.: ```d void foo(R)(R r) if (isInputRange!R && !is(R == int[])) {} void main() { foo(1); foo([1]); } ``` ``` onlineapp.d(8): Error: none of the overloads of template `onlineapp.foo` are callable using argument types `!()(int)` onlineapp.d(2): Candidate is: `foo(R)(R r)` with `R = int` must satisfy the following constraint: ` isInputRange!R` onlineapp.d(9): Error: none of the overloads of template `onlineapp.foo` are callable using argument types `!()(int[])` onlineapp.d(2): Candidate is: `foo(R)(R r)` with `R = int[]` must satisfy the following constraint: ` !is(R == int[])` ``` and I also do know that the original `isInputRange` code was like you proposed -- one lambda with all the things.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.Makes sense, although I don't get that on my machine with dmd v2.101.0: ```d import std.range; int f(R)() if (isInputRange!R) => 2; int i = f!int; ``` ``` isinputrange.d(68): Error: template instance `isinputrange.f!int` does not match template declaration `f(R)()` with `R = int` must satisfy the following constraint: ` isInputRange!R` ``` That's it, nothing about why isInputRange failed. Maybe I'm doing something wrong.Anyway, assuming dmd can use that I wonder if this would work (aside from the inout issue): ```d template isInputRange(R) { extern R r; // dummy enum isInputRange = 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; })); } ``` dmd could still see through the eponymous template to the expression, in theory.I don't know if that works, would it fail to link? It's an interesting idea.Yes, that's what I found that worked. You need the lambda parameter to mimic the mutability of the type. Which kind of sucks, but it's what we have right now. `lvalueOf!R` would work too, I just figured it isn't needed. I wonder what the cost of using `T.init` is vs. a cached lookup of a template. It's probably pretty small, but these are the kinds of things that are unintuitive.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.OK, so `typeof((R r) { return r.empty; } (R.init))` works with inout.Thanks for the blog post BTW.You're welcome! I write blog posts too infrequently, but I do have a bunch of half-started ones. I'm working on another right now...I believe so. I'm not 100% sure why we are checking for redefined init here, but apparently it's needed somewhere inside phobos. -SteveI 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.Is that validation to detect types with redefined `init`? I didn't realize Phobos needs to care about that.
Feb 19 2023
On Sunday, 19 February 2023 at 18:08:28 UTC, Steven Schveighoffer wrote:On 2/18/23 2:25 PM, Nick Treleaven wrote:OK, it could be implemented. Perhaps with complex failing constraints it would be too much information if it recursed into each template predicate too (though could be done with `-v`).That's it, nothing about why isInputRange failed. Maybe I'm doing something wrong.uhh... I think I am wrong on the reasoning then. I thought it would keep going down into the constraint, but it doesn't? Maybe it was planned?It doesn't cause a link error on my Linux machine, probably the linker detects it's not actually used anywhere. But declaring an `extern` variable of a type that contains `inout` data is an error: ``` isinputrange.d(54): Error: variable `isinputrange.isInputRange!(inout(int)[]).r` only parameters or stack based variables can be `inout` ``` So this pattern won't work.(aside from the inout issue): ```d template isInputRange(R) { extern R r; // dummy enum isInputRange = 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; })); } ``` dmd could still see through the eponymous template to the expression, in theory.I don't know if that works, would it fail to link? It's an interesting idea.Would be nice if that rule didn't apply when the `inout` data is a member of another type you're instantiating.Yes, that's what I found that worked. You need the lambda parameter to mimic the mutability of the type. Which kind of sucks, but it's what we have right now.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.OK, so `typeof((R r) { return r.empty; } (R.init))` works with inout.Great!Thanks for the blog post BTW.You're welcome! I write blog posts too infrequently, but I do have a bunch of half-started ones. I'm working on another right now...
Feb 19 2023
On Monday, 16 January 2023 at 04:30:25 UTC, Steven Schveighoffer wrote:In this post: https://forum.dlang.org/post/tm3p0p$2js2$1 digitalmars.com I mentioned:Looks like :handwaves: given a 2.4Ghz processor, that'd be 150k cycles per ReturnType instantiation? Not super much, but not nothing either. If that distributes over five templates, it'd be something like 30k for a template instantiation in general. For something that hits the allocator a few times, that seems ... about right? Indicating to me that if we want this to be fast, we have to find a way to make a template instantiation *do less.* I think that's gonna be a hard sell, given that the instantiation absolutely has to make a copy of the entire template body AST given the compiler design as it is. Looking at a profiler, how would you say these cycles are distributed between "copy tree" and "walk tree for semantic"?I did a test on something I was working on for my talk, and I'm going to write a blog post about it, because I'm kind of stunned at the results.Well, I finally got around to it: https://www.schveiguy.com/blog/2023/01/the-cost-of-compile-time-in-d/ Let me know what you think. -Steve
Jan 16 2023
On Monday, 16 January 2023 at 09:12:59 UTC, FeepingCreature wrote:On Monday, 16 January 2023 at 04:30:25 UTC, Steven Schveighoffer wrote:Processors these days are both faster than that and have pretty good IPC compiling D code so it's worse.In this post: https://forum.dlang.org/post/tm3p0p$2js2$1 digitalmars.com I mentioned:Looks like :handwaves: given a 2.4Ghz processor, that'd be 150k cycles per ReturnType instantiation? Not super much, but not nothing either. If that distributes over five templates, it'd be something like 30k for a template instantiation in general. For something that hits the allocator a few times, that seems ... about right?I did a test on something I was working on for my talk, and I'm going to write a blog post about it, because I'm kind of stunned at the results.Well, I finally got around to it: https://www.schveiguy.com/blog/2023/01/the-cost-of-compile-time-in-d/ Let me know what you think. -SteveIndicating to me that if we want this to be fast, we have to find a way to make a template instantiation *do less.* I think that's gonna be a hard sell, given that the instantiation absolutely has to make a copy of the entire template body AST given the compiler design as it is.A lot of these copies are made defensively — some of them are actually required, or at least require a different theoretical model of compilation to be avoided, whereas others are basically just made to avoid mutating the original AST. Some of this just boils down to not having a const-first attitude, other things are harder. Making more things const makes avoiding these copies easier. I was fiddling around with a dmd patch that automatically spits out a diff that adds const to things where it can.Looking at a profiler, how would you say these cycles are distributed between "copy tree" and "walk tree for semantic"?A *lot* of dmd compilation is spent doing memcpy. However I think it's actually mostly caused by CTFE arrays being shunted around. The thing to do for those arrays is probably to refcount them so the copy on write can be done in place for the hopefully common case.
Jan 16 2023
On 1/16/23 4:12 AM, FeepingCreature wrote:On Monday, 16 January 2023 at 04:30:25 UTC, Steven Schveighoffer wrote:Absolutely, I welcome any improvements that bring the current phobos into line with the improved version. I would imagine *some* penalty for ReturnType, regardless of how much can be improved. And of course, there's the whole question of "is this the right abstraction to use?". Would there be a better way to write ReturnType that doesn't cost as much, maybe using CTFE? I don't know enough about the actual implementation, so its hard for me to have a productive discussion on it. All I can do is try things and measure. -SteveIn this post: https://forum.dlang.org/post/tm3p0p$2js2$1 digitalmars.com I mentioned:Looks like :handwaves: given a 2.4Ghz processor, that'd be 150k cycles per ReturnType instantiation? Not super much, but not nothing either. If that distributes over five templates, it'd be something like 30k for a template instantiation in general. For something that hits the allocator a few times, that seems ... about right? Indicating to me that if we want this to be fast, we have to find a way to make a template instantiation *do less.* I think that's gonna be a hard sell, given that the instantiation absolutely has to make a copy of the entire template body AST given the compiler design as it is.I did a test on something I was working on for my talk, and I'm going to write a blog post about it, because I'm kind of stunned at the results.Well, I finally got around to it: https://www.schveiguy.com/blog/2023/01/the-cost-of-compile-time-in-d/ Let me know what you think.
Jan 16 2023
On Monday, 16 January 2023 at 04:30:25 UTC, Steven Schveighoffer wrote:In this post: https://forum.dlang.org/post/tm3p0p$2js2$1 digitalmars.com I mentioned:Pretty interesting this post! Although that really makes me sad because it only shows we can't really create helpers or use D effectively. I wish we could create a better thing for that.I did a test on something I was working on for my talk, and I'm going to write a blog post about it, because I'm kind of stunned at the results.Well, I finally got around to it: https://www.schveiguy.com/blog/2023/01/the-cost-of-compile-time-in-d/ Let me know what you think. -Steve
Jan 16 2023
On Sun, Jan 15, 2023 at 11:30:25PM -0500, Steven Schveighoffer via Digitalmars-d wrote: [...]https://www.schveiguy.com/blog/2023/01/the-cost-of-compile-time-in-d/[...] Honestly, I find templates like ReturnType in std.traits a bit of a code smell. Same thing as Parameters, and a whole bunch of others. Yes, it has a pretty-sounding name, and yes, you get to avoid writing that squint-inducing __traits(...) syntax, but if you take a step back, it just begs the question, why can't we do this directly in the language itself? You pointed out that there are various reasons for it -- no easy way of getting an instance of the type, need to handle different kinds of callables, etc., but to me, those are all merely circumstantial issues. It begs the question, why *isn't* there a construct to obtain an instance of some type T (even if hypothetical, for the purposes of introspection)? After all, the compiler knows T inside-out, and ought to be able to cook up a (virtual) instance of it. The crux of the problem is that the in spite of D's metaprogramming prowess being often promoted, the language *itself* doesn't let you do certain common things easily. It lets you use, e.g., typeof() in certain cases, but in other cases you need this or that workaround or paraphrasis, and so another std.traits wrapper template is born. If the language had instead been extended so that you could, for example, extract the return type of some given callable directly, say typeof(return(myfunc)), then none of this would have been necessary in the first place. Having wrappers in Phobos for doing certain things makes sense when a particular feature or introspective capability is still new / newly discovered: it wasn't anticipated so the language doesn't have a construct to express it directly, so a Phobos template helps to wrap it up in a nicer, more friendly and usable form for end users to use. But once a particular construct has become recurrent and a standard part of D idiom, it deserves to be baked into the language directly. Especially when doing so eliminates a lot of the collateral costs. T -- What's an anagram of "BANACH-TARSKI"? BANACH-TARSKI BANACH-TARSKI.
Jan 17 2023
On 1/17/2023 1:58 PM, H. S. Teoh wrote:If the language had instead been extended so that you could, for example, extract the return type of some given callable directly, say typeof(return(myfunc)), then none of this would have been necessary in the first place.https://dlang.org/spec/expression.html#is_expression int func(); static if (is(typeof(func) R == return)) pragma(msg, R); prints: int The implementation of std.traits.ReturnType is: template ReturnType(alias func) if (isCallable!func) { static if (is(FunctionTypeOf!func R == return)) alias ReturnType = R; else static assert(0, "argument has no return type"); } ReturnType can do a little more than the raw IsExpression, as it can identify: struct G { int opCall (int i) { return 1;} }
Jan 18 2023
On 1/18/23 5:20 PM, Walter Bright wrote:On 1/17/2023 1:58 PM, H. S. Teoh wrote:I didn't think of making ReturnType simplified (we know in this case the thing is not anything except a normal lambda function). I did this now: ```d template RT(alias sym) { static if(is(typeof(sym) R == return)) alias RT = R; else static assert(false, "bad"); } ... else version(useIsExpr) { enum isInputRange(R) = is(typeof(R.init) == R) && is(RT!((R r) => r.empty) == bool) && (is(typeof((return ref R r) => r.front)) || is(typeof(ref (return ref R r) => r.front))) && !is(RT!((R r) => r.front) == void) && is(typeof((R r) => r.popFront)); } ``` The result is still not as good as just using typeof directly, but much much better. When compared to a direct typeof, it adds about 0.15s of total compile time for 10000 instances, and adds 100MB more memory usage. My point still stands -- *inside* a constraint template, you should avoid using all kinds of convenience templates if you can help it. Nobody cares about the implementation of `isInputRange`, as long as it gives the right answer. Now, Adam has a point (in his comment on my blog) that if you are *already* using such convenience templates elsewhere on the *same parameters*, then this can have a negative effect on overall performance, because the caching of the template answer can speed up the compilation. In this case, the template instantiation is guaranteed to be unique since these are lambda expressions, so that doesn't apply. I think we can all agree though that it is less than ideal to have to worry about the internal details of how templates are implemented. -SteveIf the language had instead been extended so that you could, for example, extract the return type of some given callable directly, say typeof(return(myfunc)), then none of this would have been necessary in the first place.https://dlang.org/spec/expression.html#is_expression int func(); static if (is(typeof(func) R == return)) pragma(msg, R); prints: int The implementation of std.traits.ReturnType is: template ReturnType(alias func) if (isCallable!func) { static if (is(FunctionTypeOf!func R == return)) alias ReturnType = R; else static assert(0, "argument has no return type"); } ReturnType can do a little more than the raw IsExpression, as it can identify: struct G { int opCall (int i) { return 1;} }
Jan 19 2023
On Thursday, 19 January 2023 at 15:19:06 UTC, Steven Schveighoffer wrote:On 1/18/23 5:20 PM, Walter Bright wrote:On 1/17/2023 1:58 PM, H. S. Teoh wrote:I think we can all agree though that it is less than ideal to have to worry about the internal details of how templates are implemented. -Stevei disagree with this. - it makes the library harder to maintain. - it hides the actual problem. - people writing their own code will still be left with the problem.
Jan 19 2023
On 1/19/23 11:22 AM, Commander Zot wrote:On Thursday, 19 January 2023 at 15:19:06 UTC, Steven Schveighoffer wrote:I'm not sure I understand your disagreement with the quote. I think we are saying the same thing? -SteveOn 1/18/23 5:20 PM, Walter Bright wrote:On 1/17/2023 1:58 PM, H. S. Teoh wrote:I think we can all agree though that it is less than ideal to have to worry about the internal details of how templates are implemented.i disagree with this. - it makes the library harder to maintain. - it hides the actual problem. - people writing their own code will still be left with the problem.
Jan 19 2023
On Thursday, 19 January 2023 at 16:39:17 UTC, Steven Schveighoffer wrote:On 1/19/23 11:22 AM, Commander Zot wrote:maybe i misunderstand your point, but let me express my thoughts a bit more: we should worry about the internal details of how templates are implemented. they should be implemented in the most idiomatic way. manually optimising the code and making it harder to understand is suboptimal. and doing it won't fix the same problem in user code. it really just hides it.On Thursday, 19 January 2023 at 15:19:06 UTC, Steven Schveighoffer wrote:I'm not sure I understand your disagreement with the quote. I think we are saying the same thing? -SteveOn 1/18/23 5:20 PM, Walter Bright wrote:On 1/17/2023 1:58 PM, H. S. Teoh wrote:I think we can all agree though that it is less than ideal to have to worry about the internal details of how templates are implemented.i disagree with this. - it makes the library harder to maintain. - it hides the actual problem. - people writing their own code will still be left with the problem.
Jan 19 2023
On 1/19/23 11:56 AM, Commander Zot wrote:On Thursday, 19 January 2023 at 16:39:17 UTC, Steven Schveighoffer wrote:Yes, this is what I said "less than ideal to have to worry about the internal details". Ideally, we should be able to use as much templates as we want, and pay a minimal cost. Now, to be sure, we are going to pay a cost. It just shouldn't be so expensive that it causes abandonment of D for it (some recent examples noted on these forums). Making Phobos constraint templates less costly is a worthy goal, whether it's done via reducing the cost of templates overall, or finding less expensive ways to implement them. Worth noting that the compiler can't just be completely magic, sometimes you do have to rearrange things to get it to work better. -SteveOn 1/19/23 11:22 AM, Commander Zot wrote:maybe i misunderstand your point, but let me express my thoughts a bit more: we should worry about the internal details of how templates are implemented. they should be implemented in the most idiomatic way.On Thursday, 19 January 2023 at 15:19:06 UTC, Steven Schveighoffer wrote:I'm not sure I understand your disagreement with the quote. I think we are saying the same thing?I think we can all agree though that it is less than ideal to have to worry about the internal details of how templates are implemented.i disagree with this. - it makes the library harder to maintain. - it hides the actual problem. - people writing their own code will still be left with the problem.
Jan 19 2023