Fun with templates

Manu turkeyman at gmail.com
Sat Jul 13 06:50:13 PDT 2013


On 8 July 2013 21:16, Martin Nowak <code at 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 :(
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.puremagic.com/pipermail/digitalmars-d/attachments/20130713/a473bd7e/attachment.html>


More information about the Digitalmars-d mailing list