July 07, 2013 Re: Fun with templates | ||||
---|---|---|---|---|
| ||||
Posted in reply to Dicebot | On Sunday, 7 July 2013 at 17:48:17 UTC, Dicebot wrote:
> On Saturday, 6 July 2013 at 18:54:16 UTC, TommiT wrote:
>> He's talking about changing the semantics only on POD types, like int, struct of ints, static array of ints... only types that can implicitly convert from immutable to mutable.
>
> Than it does not really solve anything. Have you measured how much template bloat comes from common meta-programming tools like std.algorithm and how much - from extra instances for qualified POD types? It is better to solve broad problem instead and get this special case for free, not add more special cases in a desperate attempts to contain it.
Basically all I know about the performance issue being discussed here is that: "Code bloat is bad, m'kay". But note that Artur's suggestion would also change language semantics to a more sensible and convenient default. For example:
void foo(T)(T value)
if (isIntegral!T)
{
value = 42;
}
...I can feel free to mutate 'value' without having to worry about somebody breaking my function by calling it with an argument of type like const(int), immutable(short), shared(long) ...
|
July 08, 2013 Re: Fun with templates | ||||
---|---|---|---|---|
| ||||
Posted in reply to Dmitry Olshansky Attachments:
| On 7 July 2013 22:31, Dmitry Olshansky <dmitry.olsh@gmail.com> wrote:
> 06-Jul-2013 05:34, Manu пишет:
>
>> Okay, so I feel like this should be possible, but I can't make it work... I want to use template deduction to deduce the argument type, but I want the function arg to be Unqual!T of the deduced type, rather than the verbatim type of the argument given.
>>
>> I've tried: void f(T : Unqual!U, U)(T a) {}
>> and: void f(T)(Unqual!T a) {}
>>
>
> The thing is that if even if you somehow force your way past IFTI what would be generated is:
>
> f!(const int)(int arg);
> f!(immutable int)(int arg);
> f!(shared int)(int arg);
> f!(const shared int)(int arg);
>
> Which IMHO falls short of desired goal.
> Short of using a forwarding thunk (that you don't like, but if there was
> force_inline?) we'd have to hack the compiler.
Hmmm, this is an interesting point.
I initially thought this was desirable, it could be useful.
But now that you point it out, I guess the point you are making is that
they will all mangle separately anyway?
That seems problematic, because since all have the same return value and
physical arguments, how does the compiler choose an overload to call in
various circumstances?
I think I (mistakenly?) presumed they would all mangle the same, since they
have the same physical signature (return value + physical args), and
therefore all be the same function (eliminating the duplicates).
|
July 08, 2013 Re: Fun with templates | ||||
---|---|---|---|---|
| ||||
Posted in reply to Marco Leise | On 07/07/2013 01:19 PM, Marco Leise wrote: > If you wanted to save on template instantiations for every > possible attribute combination, you are doing it wrong. Those > are already 3 duplicate templates with binary identical > functions foo(int a) in them, which makes me cry on the inside. There is a linker optimization to get rid of the duplicates. http://msdn.microsoft.com/en-us/library/bxwfs976(v=vs.110).aspx |
July 08, 2013 Re: Fun with templates | ||||
---|---|---|---|---|
| ||||
Posted in reply to Manu | On 2013-07-08 04:10, Manu wrote: > Hmmm, this is an interesting point. > I initially thought this was desirable, it could be useful. > But now that you point it out, I guess the point you are making is that > they will all mangle separately anyway? > That seems problematic, because since all have the same return value and > physical arguments, how does the compiler choose an overload to call in > various circumstances? > I think I (mistakenly?) presumed they would all mangle the same, since > they have the same physical signature (return value + physical args), > and therefore all be the same function (eliminating the duplicates). Template arguments are part of the mangled name. Example: int foo (string a) (int b) { return b; } int bar (int b) { return b; } assert(foo!("a").mangleof == "_D4main17__T3fooVAyaa1_61Z3fooFNaNbNfiZi"); assert(foo!("abcdefg").mangleof == "_D4main29__T3fooVAyaa7_61626364656667Z3fooFNaNbNfiZi"); assert(bar.mangleof == "_D4main3barFiZi"); -- /Jacob Carlborg |
July 08, 2013 Re: Fun with templates | ||||
---|---|---|---|---|
| ||||
Posted in reply to Martin Nowak | On Monday, 8 July 2013 at 03:03:30 UTC, Martin Nowak wrote:
> On 07/07/2013 01:19 PM, Marco Leise wrote:
>> If you wanted to save on template instantiations for every
>> possible attribute combination, you are doing it wrong. Those
>> are already 3 duplicate templates with binary identical
>> functions foo(int a) in them, which makes me cry on the inside.
>
> There is a linker optimization to get rid of the duplicates.
> http://msdn.microsoft.com/en-us/library/bxwfs976(v=vs.110).aspx
Linker alone can't possibly know all required information to make a proper clean up - and duplicates are not main bloat cause. It needs to work in team with a compiler, possibly with a help of a type system.
|
July 08, 2013 Re: Fun with templates | ||||
---|---|---|---|---|
| ||||
Posted in reply to Manu | On 07/06/2013 03:34 AM, Manu wrote: > Okay, so I feel like this should be possible, but I can't make it work... > I want to use template deduction to deduce the argument type, but I want > the function arg to be Unqual!T of the deduced type, rather than the > verbatim type of the argument given. > > I've tried: void f(T : Unqual!U, U)(T a) {} > and: void f(T)(Unqual!T a) {} > > Ie, if called with: > const int x; > f(x); > Then f() should be generated void f(int) rather than void f(const int). > I can't find the Bugzilla entry right now, but we discussed before why it is not generally possible to deduce A from a match of type B with Template!A. Basically you'd need the inverse of the Template and the type mapping would need to be bijectiv. What does work though and looks similar is to deduce A from a match of Template!B with Template!A. > I don't want a million permutations of the template function for each > combination of const/immutabe/shared/etc, which especially blows out > when the function has 2 or more args. > > Note: T may only be a primitive type. Obviously const(int*) can never be > passed to int*. There is a linker optimization that would get rid of the duplicates. http://stackoverflow.com/questions/15168924/gcc-clang-merging-functions-with-identical-instructions-comdat-folding I came up with "out-of-bound" template instantiations to avoid unneeded instantiations. What you do is to forward common template code to another template that is next to the actual template. The next to is important because it allows to merge identical instantiations. For example this idiom is useful when you pass additional arguments to your template, e.g. __FILE__ and __LINE__. void _f(T)(T a) {} void f(T)(T a) { return _f!(Unqual!T)(a); } template _f(CommonArgs) { enum _f = foo!CommonArgs; } template f(CommonArgs, MoreArgs) { static assert(bar!MoreArgs); enum f = _f!CommonArgs; } |
July 13, 2013 Re: Fun with templates | ||||
---|---|---|---|---|
| ||||
Posted in reply to Martin Nowak Attachments:
| On 8 July 2013 21:16, Martin Nowak <code@dawg.eu> wrote: > On 07/06/2013 03:34 AM, Manu wrote: > >> Okay, so I feel like this should be possible, but I can't make it work... I want to use template deduction to deduce the argument type, but I want the function arg to be Unqual!T of the deduced type, rather than the verbatim type of the argument given. >> >> I've tried: void f(T : Unqual!U, U)(T a) {} >> and: void f(T)(Unqual!T a) {} >> >> Ie, if called with: >> const int x; >> f(x); >> Then f() should be generated void f(int) rather than void f(const int). >> >> I can't find the Bugzilla entry right now, but we discussed before why > it is not generally possible to deduce A from a match of type B with Template!A. Basically you'd need the inverse of the Template and the type mapping would need to be bijectiv. > > What does work though and looks similar is to deduce A from a match of Template!B with Template!A. I'm not sure I follow. Can you demonstrate? I don't want a million permutations of the template function for each >> combination of const/immutabe/shared/etc, which especially blows out when the function has 2 or more args. >> >> Note: T may only be a primitive type. Obviously const(int*) can never be >> passed to int*. >> > > There is a linker optimization that would get rid of the duplicates. > http://stackoverflow.com/**questions/15168924/gcc-clang-** > merging-functions-with-**identical-instructions-comdat-**folding<http://stackoverflow.com/questions/15168924/gcc-clang-merging-functions-with-identical-instructions-comdat-folding> > > I came up with "out-of-bound" template instantiations to avoid unneeded > instantiations. > What you do is to forward common template code to another template that is > next to the actual template. The next to is important because it allows to > merge identical instantiations. > For example this idiom is useful when you pass additional arguments to > your template, e.g. __FILE__ and __LINE__. > > void _f(T)(T a) {} > void f(T)(T a) { return _f!(Unqual!T)(a); } > > template _f(CommonArgs) { enum _f = foo!CommonArgs; } > template f(CommonArgs, MoreArgs) { static assert(bar!MoreArgs); enum f = > _f!CommonArgs; } > I really hate relying on linker optimisations to clean up mess like this, which simply shouldn't exist in the first place. Debugging is critically important. In my experience, most programmers spend 90% of their time debugging, and that means debug builds still need to be usable. Unoptimised code isn't THAT much slower/bigger by nature. But there's a big different between 10 times slower and 100 times slower. Likewise, there's also a big difference between twice as big, and 10 times as big. Depending on the optimiser to eliminate this sort of duplication tends your debug code towards the latter. At my prior company, we were very proud that our debug build still ran at ~10fps (playable/testable)... most companies debug builds run closer to 1fps or less, which means you can't practically test AND debug your code. It's very hard to reveal the bug you're chasing if you can't physically test the build. Every new person we employed was amazed, and commented on this. It was without doubt, a strategic advantage for our company. And the reason we succeeded to this end, was simply because we banned C++ (well, most of it) :/ D makes templates so convenient, one can imagine the typical situation might even be worse than typical C++. So instead, D needs to take the opportunity to offer tools to allow the programmer to express what they actually want, rather than generating copious bloat, and expecting optimisation passes to clean it up. Forwarding to secondary functions like this is really horrible. So now my 'optimisation' (it's not an optimisation, it's just what I want to do in the first place) requires that I mutilate my code. What are the sensible naming conventions for this scheme? Does this really improve readability? What about find-in-files/go-to-definition? I'm sure we can do better than this... actually, we must. I won't accept this. Bloat should be factored out by design. It's not something that should be ignored, and then attempted to clean up later. So I'm back where I started :/ Again, from the top, I want more control over the template argument deduction. I want this for example: void f(T)(Unqual!T arg); When called with: int x; const(int) cx; immutable(int) ix; shared(int) sx; f(x); f(cx); f(ix); f(sx); All calls deduce the template instantiation: void f(int)(int arg); I can see why my example syntax doesn't work. The 'T' in the argument list is actually the inverse of what I want, like you say. But I'm sure there are tweaks on the expression that could possibly make sense somehow. Basically, is it possible? Is there another approach that could produce the same outcome; that is, having more control over the template argument deduction, and consequently, the resulting template instantiation? Some creative thought can surely crack this nut. I think this is a severe issue, and worth some serious attention. I'm rather surprised how few of the heavy weights have commented on this topic :( |
Copyright © 1999-2021 by the D Language Foundation