www.digitalmars.com         C & C++   DMDScript  

digitalmars.D - Fun with templates

reply Manu <turkeyman gmail.com> writes:
--089e0160c35a91a3b104e0cdd19e
Content-Type: text/plain; charset=UTF-8

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

--089e0160c35a91a3b104e0cdd19e
Content-Type: text/html; charset=UTF-8
Content-Transfer-Encoding: quoted-printable

<div dir=3D"ltr">Okay, so I feel like this should be possible, but I can&#3=
9;t make it work...<div style>I want to use template deduction to deduce th=
e 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.</div>
<div style><br></div><div style>I&#39;ve tried: void f(T : Unqual!U, U)(T a=
) {}</div><div style>and: void f(T)(Unqual!T a) {}<br></div><div style><br>=
</div><div style>Ie, if called with:</div><div style>=C2=A0 const int x;</d=
iv>
<div style>=C2=A0 f(x);</div><div style>Then f() should be generated void f=
(int) rather than void f(const int).</div><div style><br></div><div style>I=
 don&#39;t want a million permutations of the template function for each co=
mbination of const/immutabe/shared/etc, which especially blows out when the=
 function has 2 or more args.</div>
<div style><br></div><div style>Note: T may only be a primitive type. Obvio=
usly const(int*) can never be passed to int*.</div></div>

--089e0160c35a91a3b104e0cdd19e--
Jul 05 2013
next sibling parent "Daniel Murphy" <yebblies nospamgmail.com> writes:
"Manu" <turkeyman gmail.com> wrote in message 
news:mailman.1752.1373074509.13711.digitalmars-d puremagic.com...
 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 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*.

void f(T)(T _a) { Unqual!T a = _a; ... }
Jul 05 2013
prev sibling next sibling parent "finalpatch" <fengli gmail.com> writes:
On Saturday, 6 July 2013 at 01:35:09 UTC, 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 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*.

this? template f(T) { void f (T x) { f_i(x); } void f_i(Unqual!T x) { writefln("%s", x); } }
Jul 05 2013
prev sibling next sibling parent "Vladimir Panteleev" <vladimir thecybershadow.net> writes:
On Saturday, 6 July 2013 at 01:35:09 UTC, Manu wrote:
 Okay, so I feel like this should be possible, but I can't make 
 it work...

I don't think D's IFTI allows different argument and parameter types... I think this is possible with a proxy function (a function that accepts arguments with any qualifiers, but forwards them to the real function after stripping away top-level qualifiers). Should be possible to create something that auto-generates such a proxy function. A small proxy function will likely be inlined, and would avoid template bloat. Another possible way: Unqual!T unqual(T)(T v) { return v; } Then use unqual(x) whenever calling the function (although you'd have to remember to, which sucks).
Jul 05 2013
prev sibling next sibling parent Timon Gehr <timon.gehr gmx.ch> writes:
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 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*.

void f(T)(const(T) a) {} This will strip off const, immutable and inout, but not shared. I'd have thought that void f(T)(const(shared(T)) a) {} would strip shared as well, but DMD does not match int to const(shared(int)) at all which I think is incorrect.
Jul 05 2013
prev sibling next sibling parent reply Manu <turkeyman gmail.com> writes:
--089e013a282c1958b304e0cf7630
Content-Type: text/plain; charset=UTF-8

On 6 July 2013 11:41, Daniel Murphy <yebblies nospamgmail.com> wrote:

 "Manu" <turkeyman gmail.com> wrote in message
 news:mailman.1752.1373074509.13711.digitalmars-d puremagic.com...
 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 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*.

void f(T)(T _a) { Unqual!T a = _a; ... }

That doesn't do what I want at all. The signature is still f(T) not f(Unqual!T). --089e013a282c1958b304e0cf7630 Content-Type: text/html; charset=UTF-8 Content-Transfer-Encoding: quoted-printable <div dir=3D"ltr">On 6 July 2013 11:41, Daniel Murphy <span dir=3D"ltr">&lt;= <a href=3D"mailto:yebblies nospamgmail.com" target=3D"_blank">yebblies nosp= amgmail.com</a>&gt;</span> wrote:<br><div class=3D"gmail_extra"><div class= =3D"gmail_quote"> <blockquote class=3D"gmail_quote" style=3D"margin:0 0 0 .8ex;border-left:1p= x #ccc solid;padding-left:1ex"><br> &quot;Manu&quot; &lt;<a href=3D"mailto:turkeyman gmail.com">turkeyman gmail= .com</a>&gt; wrote in message<br> news:mailman.1752.1373074509.13711.digitalmars-d puremagic.com...<br> <div><div class=3D"h5">&gt; Okay, so I feel like this should be possible, b= ut I can&#39;t make it work...<br> &gt; I want to use template deduction to deduce the argument type, but I wa= nt<br> &gt; the function arg to be Unqual!T of the deduced type, rather than the<b= r> &gt; verbatim type of the argument given.<br> &gt;<br> &gt; I&#39;ve tried: void f(T : Unqual!U, U)(T a) {}<br> &gt; and: void f(T)(Unqual!T a) {}<br> &gt;<br> &gt; Ie, if called with:<br> &gt; =C2=A0const int x;<br> &gt; =C2=A0f(x);<br> &gt; Then f() should be generated void f(int) rather than void f(const int)= .<br> &gt;<br> &gt; I don&#39;t want a million permutations of the template function for e= ach<br> &gt; combination of const/immutabe/shared/etc, which especially blows out w= hen<br> &gt; the function has 2 or more args.<br> &gt;<br> &gt; Note: T may only be a primitive type. Obviously const(int*) can never = be<br> &gt; passed to int*.<br> &gt;<br> <br> </div></div>void f(T)(T _a) { Unqual!T a =3D _a; ... }<br> </blockquote></div><br></div><div class=3D"gmail_extra" style>That doesn&#3= 9;t do what I want at all. The signature is still f(T) not f(Unqual!T).</di= v></div> --089e013a282c1958b304e0cf7630--
Jul 05 2013
parent "Daniel Murphy" <yebblies nospamgmail.com> writes:
"Manu" <turkeyman gmail.com> wrote in message 
news:mailman.1754.1373081562.13711.digitalmars-d puremagic.com...
 On 6 July 2013 11:41, Daniel Murphy <yebblies nospamgmail.com> wrote:

 "Manu" <turkeyman gmail.com> wrote in message
 news:mailman.1752.1373074509.13711.digitalmars-d puremagic.com...
 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 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*.

void f(T)(T _a) { Unqual!T a = _a; ... }

That doesn't do what I want at all. The signature is still f(T) not f(Unqual!T).

Yeah it's possible I didn't finish reading your post.
Jul 05 2013
prev sibling next sibling parent Manu <turkeyman gmail.com> writes:
--089e0160c35a7c581c04e0cf7a73
Content-Type: text/plain; charset=UTF-8

On 6 July 2013 11:42, finalpatch <fengli gmail.com> wrote:

 On Saturday, 6 July 2013 at 01:35:09 UTC, 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 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*.

this? template f(T) { void f (T x) { f_i(x); } void f_i(Unqual!T x) { writefln("%s", x); } }

And again, f(T), the signature is wrong. There is also an additional call... twice as slow when non-optimised :/ --089e0160c35a7c581c04e0cf7a73 Content-Type: text/html; charset=UTF-8 Content-Transfer-Encoding: quoted-printable <div dir=3D"ltr">On 6 July 2013 11:42, finalpatch <span dir=3D"ltr">&lt;<a = href=3D"mailto:fengli gmail.com" target=3D"_blank">fengli gmail.com</a>&gt;= </span> wrote:<br><div class=3D"gmail_extra"><div class=3D"gmail_quote"><bl= ockquote class=3D"gmail_quote" style=3D"margin:0 0 0 .8ex;border-left:1px #= ccc solid;padding-left:1ex"> <div class=3D"im">On Saturday, 6 July 2013 at 01:35:09 UTC, Manu wrote:<br> <blockquote class=3D"gmail_quote" style=3D"margin:0 0 0 .8ex;border-left:1p= x #ccc solid;padding-left:1ex"> Okay, so I feel like this should be possible, but I can&#39;t make it work.= ..<br> I want to use template deduction to deduce the argument type, but I want<br=

verbatim type of the argument given.<br> <br> I&#39;ve tried: void f(T : Unqual!U, U)(T a) {}<br> and: void f(T)(Unqual!T a) {}<br> <br> Ie, if called with:<br> =C2=A0 const int x;<br> =C2=A0 f(x);<br> Then f() should be generated void f(int) rather than void f(const int).<br> <br> I don&#39;t want a million permutations of the template function for each<b= r> combination of const/immutabe/shared/etc, which especially blows out when<b= r> the function has 2 or more args.<br> <br> Note: T may only be a primitive type. Obviously const(int*) can never be<br=

</blockquote> <br></div> this?<br> <br> template f(T)<br> {<br> =C2=A0 =C2=A0 void f (T x)<br> =C2=A0 =C2=A0 {<br> =C2=A0 =C2=A0 =C2=A0 =C2=A0 f_i(x);<br> =C2=A0 =C2=A0 }<br> =C2=A0 =C2=A0 void f_i(Unqual!T x)<br> =C2=A0 =C2=A0 {<br> =C2=A0 =C2=A0 =C2=A0 =C2=A0 writefln(&quot;%s&quot;, x);<br> =C2=A0 =C2=A0 }<br> }<br> </blockquote></div><br></div><div class=3D"gmail_extra" style>And again, f(= T), the signature is wrong. There is also an additional call... twice as sl= ow when non-optimised :/</div></div> --089e0160c35a7c581c04e0cf7a73--
Jul 05 2013
prev sibling next sibling parent Manu <turkeyman gmail.com> writes:
--001a1133056e69183604e0cf97a3
Content-Type: text/plain; charset=UTF-8

On 6 July 2013 11:45, Timon Gehr <timon.gehr gmx.ch> 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 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*.

void f(T)(const(T) a) {} This will strip off const, immutable and inout, but not shared. I'd have thought that void f(T)(const(shared(T)) a) {} would strip shared as well, but DMD does not match int to const(shared(int)) at all which I think is incorrect.

So what is the signature of f() in this case? It looks like the function receives const(T), not T. It looks like it sets T to Unqual!T, but it's not T that I'm interested in, it's the function argument being deduced to the correct type. We can do impressive stuff like this: void f(T : U[N], U, size_t N)(T x); .. but I suppose in that example, T is still the supplied type verbatim, it's just performing a lot of fancy work to decompose it. So then I wonder if my question becomes, with parameter type deduction, is it an absolute requirement that the parameter type is taken to be the supplied argument's type verbatim (and not possibly something it is implicitly castable to)? Is there ANY way to flex this rule while retaining the functionality of argument type deduction? --001a1133056e69183604e0cf97a3 Content-Type: text/html; charset=UTF-8 Content-Transfer-Encoding: quoted-printable <div dir=3D"ltr">On 6 July 2013 11:45, Timon Gehr <span dir=3D"ltr">&lt;<a = href=3D"mailto:timon.gehr gmx.ch" target=3D"_blank">timon.gehr gmx.ch</a>&g= t;</span> wrote:<br><div class=3D"gmail_extra"><div class=3D"gmail_quote"><= blockquote class=3D"gmail_quote" style=3D"margin:0 0 0 .8ex;border-left:1px= #ccc solid;padding-left:1ex"> <div class=3D"im">On 07/06/2013 03:34 AM, Manu wrote:<br> </div><blockquote class=3D"gmail_quote" style=3D"margin:0 0 0 .8ex;border-l= eft:1px #ccc solid;padding-left:1ex"><div class=3D"im"> Okay, so I feel like this should be possible, but I can&#39;t make it work.= ..<br></div><div class=3D"im"> I want to use template deduction to deduce the argument type, but I want<br=

verbatim type of the argument given.<br> <br> I&#39;ve tried: void f(T : Unqual!U, U)(T a) {}<br> and: void f(T)(Unqual!T a) {}<br> <br> Ie, if called with:<br> =C2=A0 =C2=A0const int x;<br> =C2=A0 =C2=A0f(x);<br> Then f() should be generated void f(int) rather than void f(const int).<br> <br> I don&#39;t want a million permutations of the template function for each<b= r> combination of const/immutabe/shared/etc, which especially blows out<br> when the function has 2 or more args.<br> <br> Note: T may only be a primitive type. Obviously const(int*) can never be<br=

</div></blockquote> <br> void f(T)(const(T) a) {}<br> <br> This will strip off const, immutable and inout, but not shared.<br> <br> I&#39;d have thought that<br> <br> void f(T)(const(shared(T)) a) {}<br> <br> would strip shared as well, but DMD does not match int to const(shared(int)= ) at all which I think is incorrect.<br> </blockquote></div><br></div><div class=3D"gmail_extra" style>So what is th= e signature of f() in this case? It looks like the function receives const(= T), not T.</div><div class=3D"gmail_extra" style>It looks like it sets T to= Unqual!T, but it&#39;s not T that I&#39;m interested in, it&#39;s the func= tion argument being deduced to the correct type.</div> <div class=3D"gmail_extra" style><br></div><div class=3D"gmail_extra" style=
We can do impressive stuff like this:</div><div class=3D"gmail_extra" styl=

le, T is still the supplied type verbatim, it&#39;s just performing a lot o= f fancy work to decompose it.<br> </div><div class=3D"gmail_extra" style><br></div><div class=3D"gmail_extra"= style>So then I wonder if my question becomes, with parameter type deducti= on, is it an absolute requirement that the parameter type is taken to be th= e supplied argument&#39;s type verbatim (and not possibly something it is i= mplicitly castable to)?</div> <div class=3D"gmail_extra" style>Is there ANY way to flex this rule while r= etaining the functionality of argument type deduction?</div></div> --001a1133056e69183604e0cf97a3--
Jul 05 2013
prev sibling next sibling parent "Namespace" <rswhite4 googlemail.com> writes:
 That doesn't do what I want at all. The signature is still f(T) 
 not
 f(Unqual!T).

For non-const, const and immutable inout would do it. void f(T)(inout T var)
Jul 06 2013
prev sibling next sibling parent reply "monarch_dodra" <monarchdodra gmail.com> writes:
On Saturday, 6 July 2013 at 01:35:09 UTC, 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 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*.

You could just forward to an implementation template, passing explicitly the arguments. This is kind of like the "take" function making an explicit call to "Take!T" I guess. In any case, this is what I mean. -------- void foo(T)(T t) { fooImpl!(Unqual!T)(t); } void fooImpl(T)(T t) { static assert(is(Unqual!T == T)); //do it } void main() { const(int) x; foo(x); } -------- This should do what you want. foo should be completly inlined away I believe. It is a tiny bit hackish, but should work. You'll generate all flavors of foo, but only Unqual'd versions of fooImpl (which is what you care about). You can also add some "isPrimitivee!T" if you want or something. Not sure how this deals with "shared" ? In any case, you asked for "Unqual", so that's what you get ;)
Jul 06 2013
next sibling parent reply Timon Gehr <timon.gehr gmx.ch> writes:
On 07/06/2013 04:06 PM, Manu wrote:
 ...
     It seems that your code works if you put the Template Type explicit:
     ----
     import std.stdio;
     import std.traits : Unqual;

     void foo(T)(Unqual!T a) {
              writeln(typeof(a).stringof, " <-> ", T.stringof);
     }

     void main() {
              int a;
              const int b;
              immutable int c;

              //foo(c); /// Error
              foo!(typeof(a))(a);
              foo!(typeof(b))(b);
              foo!(typeof(c))(c);
     }
     ----


 Indeed, hence my point that the type deduction is the key issue here.
 It should be possible... maybe a bit tricky though.

The key issue is that the syntax void foo(T)(Unqual!T a); denotes roughly the opposite of what you think it denotes. Basically, inference is instructed to find a T, such that Unqual!T is the argument type.
Jul 06 2013
parent Artur Skawina <art.08.09 gmail.com> writes:
On 07/07/13 08:22, Manu wrote:
 On 7 July 2013 16:02, TommiT <tommitissari hotmail.com
<mailto:tommitissari hotmail.com>> wrote:
 
     On Saturday, 6 July 2013 at 23:11:26 UTC, Manu wrote:
 
         [..] I feel like it would be a much cleaner solution than any of
 
         the others presented in this thread...
 
 
     I think Artur's solution is the cleanest one because it changes the
default behaviour to a more sensible one: it is useful to keep the full type
information only if the type isn't implicitly convertible from immutable to
mutable and back again... otherwise keeping the full type information along
only causes inconvenience.
 
 
 Maybe so, but I just have my suspicions that it will never fly, and I think a
solution here is actually pretty important.
 This is demonstrably one of the biggest issues with C++, and since templates
are so much more convenient in D, I expect time will show it to be far worse in
D than it already is in C++.

It's like the virtual-by-default situation - if the default isn't fixed everybody will ignoring this issue, until it actually becomes a problem. Then they (or more likely somebody else) will have tp do a clean up pass, and then the cycle will repeat. Almost nobody will start with auto f(T=Unqual!_T)(_T val) { /*...*/ } // example new syntax Fixing "just" IFTI should be relatively safe, affecting only a tiny amount of code, if any. These kind of const changes happen more or less randomly anyway, from the POV of the called function. "const a=1; f(a+a); f(a+1);" -- this already creates two different instances of 'f(T)(T)". Yeah, fixing the expression types would be an even better idea (so that "const int + const int" == "int" etc) but that could have a larger impact, as it would affect a lot of 'auto' declarations. artur
Jul 07 2013
prev sibling next sibling parent reply Artur Skawina <art.08.09 gmail.com> writes:
On 07/06/13 13:35, Manu wrote:
 The point here is that I want more control over the signature of the
instantiated template (reduce the number of permutations generated for various
calls). Template blow-out is perhaps the biggest and most well known day-to-day
problem in C++, and tools like this may be very valuable to mitigate the
disaster.

I was going to reply that while template bloat is a real issue, it is the compiler that should deal with this (by always inlining trivial function). Then I remembered that you mentioned that you want this only for "primitive" types, and realized what your real problem is. IFTI and value types. For example: auto f(T...)(T a) {/*...*/} int a; const int b; immutable int c; f(a); f(b); f(c); This creates three instances of 'f'. And it gets much worse with a larger number of arguments... Typically all instantiations will be identical, except in cases where the 'f' implementation tries to mutate the argument(s). (This mutation is always safe when T is passed by value and T does not contain external references) IFTI should just strip the qualifiers from all value-passed POD types which contain no refs (ie no pointers, slices and classes inside). Doing that will significantly reduce template bloat, at practically no cost. It *is* a change in behavior, but there shouldn't be much code out there that sensibly relies on the 1:1 type propagation. Explicitly specifying a type will still be possible using 'typeof'. Note that this is already done for pointers; calling 'f' with the following: immutable(void)* a; const immutable(void)* b; immutable immutable(void)* c; will not create three separate instances. This is possible in the pointer case because the compiler can get away with manipulating the type. Doing this for structs would be more complicated; fixing the primitive types- (and maybe PODs) case isn't. BTW, the way D's 'auto' works contributes to the problem: const int a; auto b = a+a; auto c = a+1; f(b); f(c); uses two different 'f' instances. artur
Jul 06 2013
parent reply Artur Skawina <art.08.09 gmail.com> writes:
On 07/06/13 17:10, Dicebot wrote:
 On Saturday, 6 July 2013 at 15:05:51 UTC, Artur Skawina wrote:
 ...

It is not that simple. Consider: void f(T)(T t) { static if (T == Unqual!T) // one function body else // completely different one } Currently every template instance is completely independent and tied to exact type. I don't know of any tool to express "group of related types" concept in D other than built-in "inout".

This is exactly why i did mention that this is a breaking change and that "there shouldn't be much code out there that sensibly relies on the 1:1 type propagation." Do you think this would be a problem /in practice/? Right now IFTI chooses an expensive alternative, which is rarely required. You have to do more work to "undo" the unnecessary type propagation. This is the wrong default. "auto" makes things even worse, by increasing the number of different-but-compatible types and causing them to propagate. artur
Jul 06 2013
parent Dmitry Olshansky <dmitry.olsh gmail.com> writes:
06-Jul-2013 22:54, TommiT пишет:
 On Saturday, 6 July 2013 at 18:07:08 UTC, Dicebot wrote:
 On Saturday, 6 July 2013 at 15:38:45 UTC, Artur Skawina wrote:
 Do you think this would be a problem /in practice/?

Yes. Honestly, lot of problems. I can easily imagine template function that modifies its argument in-place for a mutable qualifier and allocates a copy for an immutable one. Templates that introspect their parameter type to format some string. Different algorithms for processing mutable and immutable versions of same container.

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.

I've seen an aggressive proposal back in the day to just do a shallow unqual on all aggregates passed by value.
 And it is not just code breakage - you propose some magic instead of
 simple well-defined semantics and so far I don't even see the detailed
 description how new system should behave.

As I understand it, it would be like what C++ does, but only for POD types. Just take const, immutable, whatever away when they're passed by value.

-- Dmitry Olshansky
Jul 06 2013
prev sibling parent Martin Nowak <code dawg.eu> writes:
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
Jul 07 2013
prev sibling next sibling parent "monarch_dodra" <monarchdodra gmail.com> writes:
On Saturday, 6 July 2013 at 08:42:45 UTC, monarch_dodra wrote:
 On Saturday, 6 July 2013 at 01:35:09 UTC, 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.

explicitly the arguments.

Hum.. just realized you explicitly wanted to do this via template deduction. I'm not sure then :/ Sorry. Hope my workaround will be useful for you? Chances are you probably already had it worked out.
Jul 06 2013
prev sibling next sibling parent Manu <turkeyman gmail.com> writes:
--089e01293f862670fa04e0d5385b
Content-Type: text/plain; charset=UTF-8

On 6 July 2013 18:23, Namespace <rswhite4 googlemail.com> wrote:

 That doesn't do what I want at all. The signature is still f(T) not
 f(Unqual!T).

For non-const, const and immutable inout would do it. void f(T)(inout T var)

Not if there's more than 1 argument, and 'inout T' is still not 'T'. --089e01293f862670fa04e0d5385b Content-Type: text/html; charset=UTF-8 <div dir="ltr">On 6 July 2013 18:23, Namespace <span dir="ltr">&lt;<a href="mailto:rswhite4 googlemail.com" target="_blank">rswhite4 googlemail.com</a>&gt;</span> wrote:<br><div class="gmail_extra"><div class="gmail_quote"> <blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"><div class="im"><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"> That doesn&#39;t do what I want at all. The signature is still f(T) not<br> f(Unqual!T).<br> </blockquote> <br></div> For non-const, const and immutable inout would do it.<br> <br> void f(T)(inout T var)<br> </blockquote></div><br></div><div class="gmail_extra" style>Not if there&#39;s more than 1 argument, and &#39;inout T&#39; is still not &#39;T&#39;.</div></div> --089e01293f862670fa04e0d5385b--
Jul 06 2013
prev sibling next sibling parent Manu <turkeyman gmail.com> writes:
--089e01295636f0611904e0d558b1
Content-Type: text/plain; charset=UTF-8

On 6 July 2013 18:45, monarch_dodra <monarchdodra gmail.com> wrote:

 On Saturday, 6 July 2013 at 08:42:45 UTC, monarch_dodra wrote:

 On Saturday, 6 July 2013 at 01:35:09 UTC, 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.

the arguments.

Hum.. just realized you explicitly wanted to do this via template deduction. I'm not sure then :/ Sorry. Hope my workaround will be useful for you? Chances are you probably already had it worked out.

Nope, still have no good idea of my own. My first 2 impulses were the best shot I had, but they didn't work. Forwarding to an Impl template doesn't really address my problem. I still end out with bucket loads of instantiations, and double-call performance will really suffer in debug builds, which might be okay if these were big functions, but they're many trivial functions, so the cost is very high. I'm getting the distinct feeling that what I want is not actually possible. Which I have to say, is rather surprising. --089e01295636f0611904e0d558b1 Content-Type: text/html; charset=UTF-8 Content-Transfer-Encoding: quoted-printable <div dir=3D"ltr">On 6 July 2013 18:45, monarch_dodra <span dir=3D"ltr">&lt;= <a href=3D"mailto:monarchdodra gmail.com" target=3D"_blank">monarchdodra gm= ail.com</a>&gt;</span> wrote:<br><div class=3D"gmail_extra"><div class=3D"g= mail_quote"> <blockquote class=3D"gmail_quote" style=3D"margin:0px 0px 0px 0.8ex;border-= left-width:1px;border-left-color:rgb(204,204,204);border-left-style:solid;p= adding-left:1ex"><div class=3D"im">On Saturday, 6 July 2013 at 08:42:45 UTC= , monarch_dodra wrote:<br> </div><blockquote class=3D"gmail_quote" style=3D"margin:0px 0px 0px 0.8ex;b= order-left-width:1px;border-left-color:rgb(204,204,204);border-left-style:s= olid;padding-left:1ex"><div class=3D"im"> On Saturday, 6 July 2013 at 01:35:09 UTC, Manu wrote:<br> <blockquote class=3D"gmail_quote" style=3D"margin:0px 0px 0px 0.8ex;border-= left-width:1px;border-left-color:rgb(204,204,204);border-left-style:solid;p= adding-left:1ex"> Okay, so I feel like this should be possible, but I can&#39;t make it work.= ..<br> I want to use template deduction to deduce the argument type, but I want<br=

verbatim type of the argument given.<br> </blockquote></div> You could just forward to an implementation template, passing explicitly th= e arguments.<br> </blockquote> <br> Hum.. just realized you explicitly wanted to do this via template deduction= . I&#39;m not sure then :/ Sorry. Hope my workaround will be useful for you= ? Chances are you probably already had it worked out.<br> </blockquote></div><br></div><div class=3D"gmail_extra" style>Nope, still h= ave no good idea of my own. My first 2 impulses were the best shot I had, b= ut they didn&#39;t work.</div><div class=3D"gmail_extra" style><br></div><d= iv class=3D"gmail_extra" style> Forwarding to an Impl template doesn&#39;t really address my problem. I sti= ll end out with bucket loads of instantiations, and double-call performance= will really suffer in debug builds, which might be okay if these were big = functions, but they&#39;re many trivial functions, so the cost is very high= .</div> <div class=3D"gmail_extra" style><br></div><div class=3D"gmail_extra" style=
I&#39;m getting the distinct feeling that what I want is not actually poss=

--089e01295636f0611904e0d558b1--
Jul 06 2013
prev sibling next sibling parent "TommiT" <tommitissari hotmail.com> writes:
On Saturday, 6 July 2013 at 10:34:04 UTC, Manu wrote:
 I'm getting the distinct feeling that what I want is not 
 actually possible.
 Which I have to say, is rather surprising.

This seems like a defect of the language. Perhaps a new language feature is needed. Something like this: void foo(inout T)(T t) { t.mutate(); } Pass a variable of type S, const(S), or mutable(S), and the function signature becomes: void foo(S); And then fails if your argument cannot be converted to mutable S.
Jul 06 2013
prev sibling next sibling parent "TommiT" <tommitissari hotmail.com> writes:
On Saturday, 6 July 2013 at 11:23:08 UTC, TommiT wrote:
 Pass a variable of type S, const(S), or mutable(S) ...

That should have been immutable(S)
Jul 06 2013
prev sibling next sibling parent Manu <turkeyman gmail.com> writes:
--001a11c2570e7be4b504e0d634ee
Content-Type: text/plain; charset=UTF-8

On 6 July 2013 21:23, TommiT <tommitissari hotmail.com> wrote:

 On Saturday, 6 July 2013 at 10:34:04 UTC, Manu wrote:

 I'm getting the distinct feeling that what I want is not actually
 possible.
 Which I have to say, is rather surprising.

This seems like a defect of the language. Perhaps a new language feature is needed. Something like this: void foo(inout T)(T t) { t.mutate(); } Pass a variable of type S, const(S), or mutable(S), and the function signature becomes: void foo(S); And then fails if your argument cannot be converted to mutable S.

The way that makes the most sense to me is: void f(T)(Unqual!T t) {} Given an immutable(T) for instance that I want to call with, it would instantiate the template with the signature void f(T), and then attempt to call it with the immutable(T). If immutable(T) is not convertible to the argument T, then it would produce a compile error as if attempting to call any such function that just receives T. The point here is that I want more control over the signature of the instantiated template (reduce the number of permutations generated for various calls). Template blow-out is perhaps the biggest and most well known day-to-day problem in C++, and tools like this may be very valuable to mitigate the disaster. --001a11c2570e7be4b504e0d634ee Content-Type: text/html; charset=UTF-8 Content-Transfer-Encoding: quoted-printable <div dir=3D"ltr">On 6 July 2013 21:23, TommiT <span dir=3D"ltr">&lt;<a href= =3D"mailto:tommitissari hotmail.com" target=3D"_blank">tommitissari hotmail= .com</a>&gt;</span> wrote:<br><div class=3D"gmail_extra"><div class=3D"gmai= l_quote"> <blockquote class=3D"gmail_quote" style=3D"margin:0 0 0 .8ex;border-left:1p= x #ccc solid;padding-left:1ex"><div class=3D"im">On Saturday, 6 July 2013 a= t 10:34:04 UTC, Manu wrote:<br> <blockquote class=3D"gmail_quote" style=3D"margin:0 0 0 .8ex;border-left:1p= x #ccc solid;padding-left:1ex"> I&#39;m getting the distinct feeling that what I want is not actually possi= ble.<br> Which I have to say, is rather surprising.<br> </blockquote> <br></div> This seems like a defect of the language. Perhaps a new language feature is= needed. Something like this:<br> <br> void foo(inout T)(T t)<br> {<br> =C2=A0 =C2=A0 t.mutate();<br> }<br> <br> Pass a variable of type S, const(S), or mutable(S), and the function signat= ure becomes:<br> <br> void foo(S);<br> <br> And then fails if your argument cannot be converted to mutable S.<br> </blockquote></div><br></div><div class=3D"gmail_extra" style>The way that = makes the most sense to me is:</div><div class=3D"gmail_extra" style><br></= div><div class=3D"gmail_extra" style>void f(T)(Unqual!T t) {}</div><div cla= ss=3D"gmail_extra" style> <br></div><div class=3D"gmail_extra" style>Given an immutable(T) for instan= ce that I want to call with, it would instantiate the template with the sig= nature void f(T), and then attempt to call it with the immutable(T). If imm= utable(T) is not convertible to the argument T, then it would produce a com= pile error as if attempting to call any such function that just receives T.= </div> <div class=3D"gmail_extra" style><br></div><div class=3D"gmail_extra" style=
The point here is that I want more control over the signature of the insta=

alls). Template blow-out is perhaps the biggest and most well known day-to-= day problem in C++, and tools like this may be very valuable to mitigate th= e disaster.</div> </div> --001a11c2570e7be4b504e0d634ee--
Jul 06 2013
prev sibling next sibling parent "TommiT" <tommitissari hotmail.com> writes:
On Saturday, 6 July 2013 at 11:35:28 UTC, Manu wrote:
 On 6 July 2013 21:23, TommiT <tommitissari hotmail.com> wrote:

 On Saturday, 6 July 2013 at 10:34:04 UTC, Manu wrote:

 I'm getting the distinct feeling that what I want is not 
 actually
 possible.
 Which I have to say, is rather surprising.

This seems like a defect of the language. Perhaps a new language feature is needed. Something like this: void foo(inout T)(T t) { t.mutate(); } Pass a variable of type S, const(S), or mutable(S), and the function signature becomes: void foo(S); And then fails if your argument cannot be converted to mutable S.

The way that makes the most sense to me is: void f(T)(Unqual!T t) {}

That would look more sensible, but I don't think that's implementable if any template could be used in the place of 'Unqual'. For example: struct Soo(T, int v) {} template Too(T, int x) { alias Too = Soo!(T, x * x - 102); } void foo(T, n)(Too!(T, n) var) {} void main() { Soo!(int, 42) var; foo(var); } It would be pretty difficult for the compiler to figure out during the instantiation of foo that T == int and n == 12. I don't know, but I suspect it's pretty impossible to implement a compiler that could figure out those template parameters for every possible scenario.
Jul 06 2013
prev sibling next sibling parent "Namespace" <rswhite4 googlemail.com> writes:
 The way that makes the most sense to me is:

 void f(T)(Unqual!T t) {}

 Given an immutable(T) for instance that I want to call with, it 
 would
 instantiate the template with the signature void f(T), and then 
 attempt to
 call it with the immutable(T). If immutable(T) is not 
 convertible to the
 argument T, then it would produce a compile error as if 
 attempting to call
 any such function that just receives T.

 The point here is that I want more control over the signature 
 of the
 instantiated template (reduce the number of permutations 
 generated for
 various calls). Template blow-out is perhaps the biggest and 
 most well
 known day-to-day problem in C++, and tools like this may be 
 very valuable
 to mitigate the disaster.

It seems that your code works if you put the Template Type explicit: ---- import std.stdio; import std.traits : Unqual; void foo(T)(Unqual!T a) { writeln(typeof(a).stringof, " <-> ", T.stringof); } void main() { int a; const int b; immutable int c; //foo(c); /// Error foo!(typeof(a))(a); foo!(typeof(b))(b); foo!(typeof(c))(c); } ----
Jul 06 2013
prev sibling next sibling parent "TommiT" <tommitissari hotmail.com> writes:
On Saturday, 6 July 2013 at 11:35:28 UTC, Manu wrote:
 The way that makes the most sense to me is:

 void f(T)(Unqual!T t) {}

But my syntax makes pretty much sense too: void foo(inout T)(T var) { var = 42; } void main() { foo!(int)(1); foo!(const int)(2); foo!(immutable int)(3); } For all those calls to foo, the type parameter T is deduced to be int, and the function template instantiates to the signature: void foo(int var); The function template foo accepts int, const(int) and immutable(int) as the type parameter, because they're all convertible to inout(int). The same kind of logic can be seen with runtime arguments, when they are qualified with something: void bar(T)(const T var) { } void main() { const int n; bar(n); } Here, similarly, the type of T is deduced to be int, even though the argument passed in is const(int).
Jul 06 2013
prev sibling next sibling parent "TommiT" <tommitissari hotmail.com> writes:
On Saturday, 6 July 2013 at 12:51:18 UTC, TommiT wrote:
 The function template foo accepts int, const(int) and 
 immutable(int) as the type parameter, because they're all 
 convertible to inout(int).

I didn't mean _convertible_ to inout, but rather that inout _accepts_ const, immutable or nothing.
Jul 06 2013
prev sibling next sibling parent "TommiT" <tommitissari hotmail.com> writes:
On Saturday, 6 July 2013 at 12:51:18 UTC, TommiT wrote:
 On Saturday, 6 July 2013 at 11:35:28 UTC, Manu wrote:
 The way that makes the most sense to me is:

 void f(T)(Unqual!T t) {}

But my syntax makes pretty much sense too: void foo(inout T)(T var) { var = 42; } void main() { foo!(int)(1); foo!(const int)(2); foo!(immutable int)(3); }

Some more details of this proposed feature: inout(T) foo(inout T)(T a, T b) { return var; } void bar(inout T)(T a, T b) { a = b; } void main() { const int con; immutable int imm; foo(con, con); // OK (returns const int) foo(con, imm); // Error: returned inout(T) is ambiguous bar(con, con); // OK bar(con, imm); // OK (no ambiguity because inout not used) }
Jul 06 2013
prev sibling next sibling parent "TommiT" <tommitissari hotmail.com> writes:
On Saturday, 6 July 2013 at 13:30:02 UTC, TommiT wrote:
 Some more details of this proposed feature:

 inout(T) foo(inout T)(T a, T b)
 {
     return var;
 }

 void bar(inout T)(T a, T b)
 {
     a = b;
 }

 void main()
 {
     const int con;
     immutable int imm;

     foo(con, con); // OK (returns const int)
     foo(con, imm); // Error: returned inout(T) is ambiguous

     bar(con, con); // OK
     bar(con, imm); // OK (no ambiguity because inout not used)
 }

Another approach, if we wanted a different syntax, would be to add a new keyword 'mutable'. Like immutable overrides const, mutable would override both const and immutable: static assert(is(mutable(const(int)) == int)); static assert(is(mutable(immutable(int)) == int)); Here's how it would look: T foo(T)(mutable(T) a, mutable(T) b) { a = b = 123; return a; } void main() { const int con; immutable int imm; foo(con, con); // OK (returns const int) foo(con, imm); // Error: T is ambiguous }
Jul 06 2013
prev sibling next sibling parent Manu <turkeyman gmail.com> writes:
--089e014951b62ae68204e0d851cf
Content-Type: text/plain; charset=UTF-8

On 6 July 2013 22:27, Namespace <rswhite4 googlemail.com> wrote:

 The way that makes the most sense to me is:
 void f(T)(Unqual!T t) {}

 Given an immutable(T) for instance that I want to call with, it would
 instantiate the template with the signature void f(T), and then attempt to
 call it with the immutable(T). If immutable(T) is not convertible to the
 argument T, then it would produce a compile error as if attempting to call
 any such function that just receives T.

 The point here is that I want more control over the signature of the
 instantiated template (reduce the number of permutations generated for
 various calls). Template blow-out is perhaps the biggest and most well
 known day-to-day problem in C++, and tools like this may be very valuable
 to mitigate the disaster.

It seems that your code works if you put the Template Type explicit: ---- import std.stdio; import std.traits : Unqual; void foo(T)(Unqual!T a) { writeln(typeof(a).stringof, " <-> ", T.stringof); } void main() { int a; const int b; immutable int c; //foo(c); /// Error foo!(typeof(a))(a); foo!(typeof(b))(b); foo!(typeof(c))(c); } ----

Indeed, hence my point that the type deduction is the key issue here. It should be possible... maybe a bit tricky though. --089e014951b62ae68204e0d851cf Content-Type: text/html; charset=UTF-8 Content-Transfer-Encoding: quoted-printable <div dir=3D"ltr">On 6 July 2013 22:27, Namespace <span dir=3D"ltr">&lt;<a h= ref=3D"mailto:rswhite4 googlemail.com" target=3D"_blank">rswhite4 googlemai= l.com</a>&gt;</span> wrote:<br><div class=3D"gmail_extra"><div class=3D"gma= il_quote"> <blockquote class=3D"gmail_quote" style=3D"margin:0 0 0 .8ex;border-left:1p= x #ccc solid;padding-left:1ex"><blockquote class=3D"gmail_quote" style=3D"m= argin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex"><div class=3D= "im"> The way that makes the most sense to me is:<br> <br> void f(T)(Unqual!T t) {}<br> <br></div><div class=3D"im"> Given an immutable(T) for instance that I want to call with, it would<br> instantiate the template with the signature void f(T), and then attempt to<= br> call it with the immutable(T). If immutable(T) is not convertible to the<br=

br> any such function that just receives T.<br> <br> The point here is that I want more control over the signature of the<br> instantiated template (reduce the number of permutations generated for<br> various calls). Template blow-out is perhaps the biggest and most well<br> known day-to-day problem in C++, and tools like this may be very valuable<b= r> to mitigate the disaster.<br> </div></blockquote> <br> It seems that your code works if you put the Template Type explicit:<br> ----<br> import std.stdio;<br> import std.traits : Unqual;<br> <br> void foo(T)(Unqual!T a) {<br> =C2=A0 =C2=A0 =C2=A0 =C2=A0 writeln(typeof(a).stringof, &quot; &lt;-&gt; &q= uot;, T.stringof);<br> }<br> <br> void main() {<br> =C2=A0 =C2=A0 =C2=A0 =C2=A0 int a;<br> =C2=A0 =C2=A0 =C2=A0 =C2=A0 const int b;<br> =C2=A0 =C2=A0 =C2=A0 =C2=A0 immutable int c;<br> <br> =C2=A0 =C2=A0 =C2=A0 =C2=A0 //foo(c); /// Error<br> =C2=A0 =C2=A0 =C2=A0 =C2=A0 foo!(typeof(a))(a);<br> =C2=A0 =C2=A0 =C2=A0 =C2=A0 foo!(typeof(b))(b);<br> =C2=A0 =C2=A0 =C2=A0 =C2=A0 foo!(typeof(c))(c);<br> }<br> ----<br> </blockquote></div><br></div><div class=3D"gmail_extra" style>Indeed, hence= my point that the type deduction is the key issue here.</div><div class=3D= "gmail_extra" style>It should be possible... maybe a bit tricky though.</di= v> </div> --089e014951b62ae68204e0d851cf--
Jul 06 2013
prev sibling next sibling parent Manu <turkeyman gmail.com> writes:
--047d7b45048250bc4b04e0d85d55
Content-Type: text/plain; charset=UTF-8

I feel like it would be much better to do this with type deduction, than to
introduce new keywords and concepts...
Saying type deduction is hard is probably not accurate. It's either
possible, or impossible. If it's mechanically possible, then it's easy for
the compiler to do. If it's impossible (or ambiguous), then an error would
be thrown in those cases. I'm sure the compiler is capable of working out
if it's impossible and complaining.


On 6 July 2013 23:50, TommiT <tommitissari hotmail.com> wrote:

 On Saturday, 6 July 2013 at 13:30:02 UTC, TommiT wrote:

 Some more details of this proposed feature:

 inout(T) foo(inout T)(T a, T b)
 {
     return var;
 }

 void bar(inout T)(T a, T b)
 {
     a = b;
 }

 void main()
 {
     const int con;
     immutable int imm;

     foo(con, con); // OK (returns const int)
     foo(con, imm); // Error: returned inout(T) is ambiguous

     bar(con, con); // OK
     bar(con, imm); // OK (no ambiguity because inout not used)
 }

Another approach, if we wanted a different syntax, would be to add a new keyword 'mutable'. Like immutable overrides const, mutable would override both const and immutable: static assert(is(mutable(const(int)) == int)); static assert(is(mutable(immutable(**int)) == int)); Here's how it would look: T foo(T)(mutable(T) a, mutable(T) b) { a = b = 123; return a; } void main() { const int con; immutable int imm; foo(con, con); // OK (returns const int) foo(con, imm); // Error: T is ambiguous }

--047d7b45048250bc4b04e0d85d55 Content-Type: text/html; charset=UTF-8 Content-Transfer-Encoding: quoted-printable <div dir=3D"ltr">I feel like it would be much better to do this with type d= eduction, than to introduce new keywords and concepts...<div style>Saying t= ype deduction is hard is probably not accurate. It&#39;s either possible, o= r impossible. If it&#39;s mechanically possible, then it&#39;s easy for the= compiler to do. If it&#39;s impossible (or ambiguous), then an error would= be thrown in those cases. I&#39;m sure the compiler is capable of working = out if it&#39;s impossible and complaining.<br> </div></div><div class=3D"gmail_extra"><br><br><div class=3D"gmail_quote">O= n 6 July 2013 23:50, TommiT <span dir=3D"ltr">&lt;<a href=3D"mailto:tommiti= ssari hotmail.com" target=3D"_blank">tommitissari hotmail.com</a>&gt;</span=
 wrote:<br>

x #ccc solid;padding-left:1ex"><div class=3D"im">On Saturday, 6 July 2013 a= t 13:30:02 UTC, TommiT wrote:<br> <blockquote class=3D"gmail_quote" style=3D"margin:0 0 0 .8ex;border-left:1p= x #ccc solid;padding-left:1ex"> Some more details of this proposed feature:<br> <br> inout(T) foo(inout T)(T a, T b)<br> {<br> =C2=A0 =C2=A0 return var;<br> }<br> <br> void bar(inout T)(T a, T b)<br> {<br> =C2=A0 =C2=A0 a =3D b;<br> }<br> <br> void main()<br> {<br> =C2=A0 =C2=A0 const int con;<br> =C2=A0 =C2=A0 immutable int imm;<br> <br> =C2=A0 =C2=A0 foo(con, con); // OK (returns const int)<br> =C2=A0 =C2=A0 foo(con, imm); // Error: returned inout(T) is ambiguous<br> <br> =C2=A0 =C2=A0 bar(con, con); // OK<br> =C2=A0 =C2=A0 bar(con, imm); // OK (no ambiguity because inout not used)<br=

</blockquote> <br></div> Another approach, if we wanted a different syntax, would be to add a new ke= yword &#39;mutable&#39;. Like immutable overrides const, mutable would over= ride both const and immutable:<br> <br> static assert(is(mutable(const(int)) =3D=3D int));<br> static assert(is(mutable(immutable(<u></u>int)) =3D=3D int));<br> <br> Here&#39;s how it would look:<br> <br> T foo(T)(mutable(T) a, mutable(T) b)<br> {<br> =C2=A0 =C2=A0 a =3D b =3D 123;<br> =C2=A0 =C2=A0 return a;<div class=3D"im"><br> }<br> <br> void main()<br> {<br> =C2=A0 =C2=A0 const int con;<br> =C2=A0 =C2=A0 immutable int imm;<br> <br> =C2=A0 =C2=A0 foo(con, con); // OK (returns const int)<br></div> =C2=A0 =C2=A0 foo(con, imm); // Error: T is ambiguous<br> }<br> </blockquote></div><br></div> --047d7b45048250bc4b04e0d85d55--
Jul 06 2013
prev sibling next sibling parent "TommiT" <tommitissari hotmail.com> writes:
On Saturday, 6 July 2013 at 13:30:02 UTC, TommiT wrote:
 Some more details of this proposed feature:

 inout(T) foo(inout T)(T a, T b)
 {
     return var;
 }

 void bar(inout T)(T a, T b)
 {
     a = b;
 }

 void main()
 {
     const int con;
     immutable int imm;

     foo(con, con); // OK (returns const int)
     foo(con, imm); // Error: returned inout(T) is ambiguous

     bar(con, con); // OK
     bar(con, imm); // OK (no ambiguity because inout not used)
 }

Some more details of a bit more complicated use case: E foo(inout T : E[3], E)(T arr) { return arr[0]; } E bar(inout T : inout(E)[3], E)(T arr) { return arr[0]; } void main() { immutable int[3] iarr; foo(iarr); // returns an immutable int bar(iarr); // returns an int }
Jul 06 2013
prev sibling next sibling parent "Dicebot" <public dicebot.lv> writes:
On Saturday, 6 July 2013 at 15:05:51 UTC, Artur Skawina wrote:
 ...

It is not that simple. Consider: void f(T)(T t) { static if (T == Unqual!T) // one function body else // completely different one } Currently every template instance is completely independent and tied to exact type. I don't know of any tool to express "group of related types" concept in D other than built-in "inout".
Jul 06 2013
prev sibling next sibling parent "Dicebot" <public dicebot.lv> writes:
On Saturday, 6 July 2013 at 01:35:09 UTC, Manu wrote:
 ...

If this is about template bloat I think much better is to address problem in general. For example, internal linkage or strict export requirements - anything that will allow to inline and completely eliminate trivial templates leaving no traces of it in final executable.
Jul 06 2013
prev sibling next sibling parent "TommiT" <tommitissari hotmail.com> writes:
On Saturday, 6 July 2013 at 15:38:45 UTC, Artur Skawina wrote:
 Do you think this would be a problem /in practice/?

To me it seems highly unlikely that this would break any code. +1 from me.
Jul 06 2013
prev sibling next sibling parent "Dicebot" <public dicebot.lv> writes:
On Saturday, 6 July 2013 at 15:38:45 UTC, Artur Skawina wrote:
 Do you think this would be a problem /in practice/?

Yes. Honestly, lot of problems. I can easily imagine template function that modifies its argument in-place for a mutable qualifier and allocates a copy for an immutable one. Templates that introspect their parameter type to format some string. Different algorithms for processing mutable and immutable versions of same container. And it is not just code breakage - you propose some magic instead of simple well-defined semantics and so far I don't even see the detailed description how new system should behave. Currently template body is defined only by its parameter set, your proposal changes that as far as I understand. I think more reasonable approach is to define "inout" in template parameter specialization to mean "I don't care what it is, make it compiler error to rely on any behavior difference between them". Don't know what to do about mangling though. Will also most likely need to prohibit and direct reference to T. It looks like extremely complex way to solve only one minor part of general problem (template bloat).
Jul 06 2013
prev sibling next sibling parent "TommiT" <tommitissari hotmail.com> writes:
On Saturday, 6 July 2013 at 18:07:08 UTC, Dicebot wrote:
 On Saturday, 6 July 2013 at 15:38:45 UTC, Artur Skawina wrote:
 Do you think this would be a problem /in practice/?

Yes. Honestly, lot of problems. I can easily imagine template function that modifies its argument in-place for a mutable qualifier and allocates a copy for an immutable one. Templates that introspect their parameter type to format some string. Different algorithms for processing mutable and immutable versions of same container.

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.
 And it is not just code breakage - you propose some magic 
 instead of simple well-defined semantics and so far I don't 
 even see the detailed description how new system should behave.

As I understand it, it would be like what C++ does, but only for POD types. Just take const, immutable, whatever away when they're passed by value.
Jul 06 2013
prev sibling next sibling parent Manu <turkeyman gmail.com> writes:
--089e01293f8681236404e0dfed50
Content-Type: text/plain; charset=UTF-8

On 7 July 2013 00:49, Timon Gehr <timon.gehr gmx.ch> wrote:

 On 07/06/2013 04:06 PM, Manu wrote:

 ...

     It seems that your code works if you put the Template Type explicit:
     ----
     import std.stdio;
     import std.traits : Unqual;

     void foo(T)(Unqual!T a) {
              writeln(typeof(a).stringof, " <-> ", T.stringof);
     }

     void main() {
              int a;
              const int b;
              immutable int c;

              //foo(c); /// Error
              foo!(typeof(a))(a);
              foo!(typeof(b))(b);
              foo!(typeof(c))(c);
     }
     ----


 Indeed, hence my point that the type deduction is the key issue here.
 It should be possible... maybe a bit tricky though.

The key issue is that the syntax void foo(T)(Unqual!T a); denotes roughly the opposite of what you think it denotes. Basically, inference is instructed to find a T, such that Unqual!T is the argument type.

Perhaps what you say is true, but does that mean something to the effect of what I'm trying to demonstrate is impossible? I feel like it would be a much cleaner solution than any of the others presented in this thread... --089e01293f8681236404e0dfed50 Content-Type: text/html; charset=UTF-8 Content-Transfer-Encoding: quoted-printable <div dir=3D"ltr">On 7 July 2013 00:49, Timon Gehr <span dir=3D"ltr">&lt;<a = href=3D"mailto:timon.gehr gmx.ch" target=3D"_blank">timon.gehr gmx.ch</a>&g= t;</span> wrote:<br><div class=3D"gmail_extra"><div class=3D"gmail_quote"><= blockquote class=3D"gmail_quote" style=3D"margin:0 0 0 .8ex;border-left:1px= #ccc solid;padding-left:1ex"> On 07/06/2013 04:06 PM, Manu wrote:<br> <blockquote class=3D"gmail_quote" style=3D"margin:0 0 0 .8ex;border-left:1p= x #ccc solid;padding-left:1ex"> ...<div class=3D"im"><br> =C2=A0 =C2=A0 It seems that your code works if you put the Template Type ex= plicit:<br> =C2=A0 =C2=A0 ----<br> =C2=A0 =C2=A0 import std.stdio;<br> =C2=A0 =C2=A0 import std.traits : Unqual;<br> <br> =C2=A0 =C2=A0 void foo(T)(Unqual!T a) {<br> =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0writeln(typeof(a).stringof,= &quot; &lt;-&gt; &quot;, T.stringof);<br> =C2=A0 =C2=A0 }<br> <br> =C2=A0 =C2=A0 void main() {<br> =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0int a;<br> =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0const int b;<br> =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0immutable int c;<br> <br> =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0//foo(c); /// Error<br> =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0foo!(typeof(a))(a);<br> =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0foo!(typeof(b))(b);<br> =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0foo!(typeof(c))(c);<br> =C2=A0 =C2=A0 }<br> =C2=A0 =C2=A0 ----<br> <br> <br></div><div class=3D"im"> Indeed, hence my point that the type deduction is the key issue here.<br> It should be possible... maybe a bit tricky though.<br> </div></blockquote> <br> The key issue is that the syntax void foo(T)(Unqual!T a); denotes roughly t= he opposite of what you think it denotes. Basically, inference is instructe= d to find a T, such that Unqual!T is the argument type.<br> </blockquote></div><br></div><div class=3D"gmail_extra" style>Perhaps what = you say is true, but does that mean something to the effect of what I&#39;m= trying to demonstrate is impossible? I feel like it would be a much cleane= r solution than any of the others presented in this thread...</div> </div> --089e01293f8681236404e0dfed50--
Jul 06 2013
prev sibling next sibling parent "TommiT" <tommitissari hotmail.com> writes:
On Saturday, 6 July 2013 at 23:11:26 UTC, Manu wrote:
 [..] I feel like it would be a much cleaner solution than any of
 the others presented in this thread...

I think Artur's solution is the cleanest one because it changes the default behaviour to a more sensible one: it is useful to keep the full type information only if the type isn't implicitly convertible from immutable to mutable and back again... otherwise keeping the full type information along only causes inconvenience.
Jul 06 2013
prev sibling next sibling parent Manu <turkeyman gmail.com> writes:
--047d7b45048248156904e0e5f29d
Content-Type: text/plain; charset=UTF-8

On 7 July 2013 16:02, TommiT <tommitissari hotmail.com> wrote:

 On Saturday, 6 July 2013 at 23:11:26 UTC, Manu wrote:

 [..] I feel like it would be a much cleaner solution than any of

 the others presented in this thread...

I think Artur's solution is the cleanest one because it changes the default behaviour to a more sensible one: it is useful to keep the full type information only if the type isn't implicitly convertible from immutable to mutable and back again... otherwise keeping the full type information along only causes inconvenience.

Maybe so, but I just have my suspicions that it will never fly, and I think a solution here is actually pretty important. This is demonstrably one of the biggest issues with C++, and since templates are so much more convenient in D, I expect time will show it to be far worse in D than it already is in C++. --047d7b45048248156904e0e5f29d Content-Type: text/html; charset=UTF-8 Content-Transfer-Encoding: quoted-printable <div dir=3D"ltr">On 7 July 2013 16:02, TommiT <span dir=3D"ltr">&lt;<a href= =3D"mailto:tommitissari hotmail.com" target=3D"_blank">tommitissari hotmail= .com</a>&gt;</span> wrote:<br><div class=3D"gmail_extra"><div class=3D"gmai= l_quote"> <blockquote class=3D"gmail_quote" style=3D"margin:0 0 0 .8ex;border-left:1p= x #ccc solid;padding-left:1ex">On Saturday, 6 July 2013 at 23:11:26 UTC, Ma= nu wrote:<br> <blockquote class=3D"gmail_quote" style=3D"margin:0 0 0 .8ex;border-left:1p= x #ccc solid;padding-left:1ex"> [..] I feel like it would be a much cleaner solution than any of<div class= =3D"im"><br> the others presented in this thread...<br> </div></blockquote> <br> I think Artur&#39;s solution is the cleanest one because it changes the def= ault behaviour to a more sensible one: it is useful to keep the full type i= nformation only if the type isn&#39;t implicitly convertible from immutable= to mutable and back again... otherwise keeping the full type information a= long only causes inconvenience.<br> </blockquote></div><br></div><div class=3D"gmail_extra" style>Maybe so, but= I just have my suspicions that it will never fly, and I think a solution h= ere is actually pretty important.</div><div class=3D"gmail_extra" style>Thi= s is demonstrably one of the biggest issues with C++, and since templates a= re so much more convenient in D, I expect time will show it to be far worse= in D than it already is in C++.</div> </div> --047d7b45048248156904e0e5f29d--
Jul 06 2013
prev sibling next sibling parent "TommiT" <tommitissari hotmail.com> writes:
On Sunday, 7 July 2013 at 06:22:17 UTC, Manu wrote:
 On 7 July 2013 16:02, TommiT <tommitissari hotmail.com> wrote:
 I think Artur's solution is the cleanest one [..]

Maybe so, but I just have my suspicions that it will never fly, and I think a solution here is actually pretty important.

You think it won't fly because it's a breaking change? I also think a solution is needed. Earlier you said that your suggestion either is implementable or it isn't. If you put it that way, the answer must be that it is implementable, because if a problem is computable then it is possible to write a compiler that can compute it given that there's an ambiguous solution to the problem. But since compiler writers are only human, I think there might the third possibility which is that it's just a too big of an undertaking for a small group of humans to write that compiler. For example here's an example where the compiler would need to solve the equation: cast(int) (3.5 ^^ x * x ^^ 4 + 5 * x) == 206 for x. And not only does the compiler need to figure out an answer to the problem, it needs to figure out that there aren't multiple answers to the problem. struct Soo(int n) { } template Too(int x) { alias Too = Soo!(cast(int) (3.5 ^^ x * x ^^ 4 + 5 * x)); } void foo(int n)(Too!n) { } void main() { Soo!206 s; foo(s); // should call foo!2(s) }
Jul 07 2013
prev sibling next sibling parent Marco Leise <Marco.Leise gmx.de> writes:
Am Sat, 6 Jul 2013 20:24:41 +1000
schrieb Manu <turkeyman gmail.com>:

 On 6 July 2013 18:23, Namespace <rswhite4 googlemail.com> wrote:
 
 That doesn't do what I want at all. The signature is still f(T) not
 f(Unqual!T).

For non-const, const and immutable inout would do it. void f(T)(inout T var)

Not if there's more than 1 argument, and 'inout T' is still not 'T'.

Hey, inout looks like a neat solution! And it only creates one template instance no matter how many arguments of type inout(T) you use! -- Marco
Jul 07 2013
prev sibling next sibling parent "TommiT" <tommitissari hotmail.com> writes:
On Sunday, 7 July 2013 at 11:07:44 UTC, Marco Leise wrote:
 Am Sat, 6 Jul 2013 20:24:41 +1000
 schrieb Manu <turkeyman gmail.com>:

 On 6 July 2013 18:23, Namespace <rswhite4 googlemail.com> 
 wrote:
 
 That doesn't do what I want at all. The signature is still 
 f(T) not
 f(Unqual!T).

For non-const, const and immutable inout would do it. void f(T)(inout T var)

Not if there's more than 1 argument, and 'inout T' is still not 'T'.

Hey, inout looks like a neat solution! And it only creates one template instance no matter how many arguments of type inout(T) you use!

const would have the same effect: void f(T)(const T var) { ... } ...but then you can't mutate var.
Jul 07 2013
prev sibling next sibling parent Marco Leise <Marco.Leise gmx.de> writes:
Am Sun, 7 Jul 2013 00:06:26 +1000
schrieb Manu <turkeyman gmail.com>:

 On 6 July 2013 22:27, Namespace <rswhite4 googlemail.com> wrote:
 
 The way that makes the most sense to me is:
 void f(T)(Unqual!T t) {}

 Given an immutable(T) for instance that I want to call with, it would
 instantiate the template with the signature void f(T), and then attempt to
 call it with the immutable(T). If immutable(T) is not convertible to the
 argument T, then it would produce a compile error as if attempting to call
 any such function that just receives T.

 The point here is that I want more control over the signature of the
 instantiated template (reduce the number of permutations generated for
 various calls). Template blow-out is perhaps the biggest and most well
 known day-to-day problem in C++, and tools like this may be very valuable
 to mitigate the disaster.

It seems that your code works if you put the Template Type explicit: ---- import std.stdio; import std.traits : Unqual; void foo(T)(Unqual!T a) { writeln(typeof(a).stringof, " <-> ", T.stringof); } void main() { int a; const int b; immutable int c; //foo(c); /// Error foo!(typeof(a))(a); foo!(typeof(b))(b); foo!(typeof(c))(c); } ----

Indeed, hence my point that the type deduction is the key issue here. It should be possible... maybe a bit tricky though.

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. -- Marco
Jul 07 2013
prev sibling next sibling parent Marco Leise <Marco.Leise gmx.de> writes:
Am Sat, 06 Jul 2013 17:10:24 +0200
schrieb "Dicebot" <public dicebot.lv>:

 On Saturday, 6 July 2013 at 15:05:51 UTC, Artur Skawina wrote:
 ...

It is not that simple. Consider: void f(T)(T t) { static if (T == Unqual!T) // one function body else // completely different one } Currently every template instance is completely independent and tied to exact type. I don't know of any tool to express "group of related types" concept in D other than built-in "inout".

Hmm, this inout stuff sounds like a possible solution... -- Marco
Jul 07 2013
prev sibling next sibling parent Marco Leise <Marco.Leise gmx.de> writes:
Am Sun, 07 Jul 2013 01:04:52 +0400
schrieb Dmitry Olshansky <dmitry.olsh gmail.com>:

 I've seen an aggressive proposal back in the day to just do a shallow 
 unqual on all aggregates passed by value.

I came to the same conclusion. If feasible, type inference should always produce tail-const versions. Well, Rebinable!T then for classes. ;) It is really annoying to have value types like ints passed in as immutable/const, just because they were at the call site. Even for array slices arguments it's sometimes neat to be able to shrink the passed slice to remove elements that you don't need to process (whitespace, zeroes, ...) -- Marco
Jul 07 2013
prev sibling next sibling parent Marco Leise <Marco.Leise gmx.de> writes:
Am Sat, 06 Jul 2013 17:24:23 +0200
schrieb "Dicebot" <public dicebot.lv>:

 On Saturday, 6 July 2013 at 01:35:09 UTC, Manu wrote:
 ...

If this is about template bloat I think much better is to address problem in general. For example, internal linkage or strict export requirements - anything that will allow to inline and completely eliminate trivial templates leaving no traces of it in final executable.

Less duplicate instantiations results in faster compile times. An area where DMD is really good and should strive to keep its pole position. -- Marco
Jul 07 2013
prev sibling next sibling parent Marco Leise <Marco.Leise gmx.de> writes:
Am Sun, 07 Jul 2013 13:17:23 +0200
schrieb "TommiT" <tommitissari hotmail.com>:

 const would have the same effect:
 
 void f(T)(const T var) { ... }
 
 ...but then you can't mutate var.

That doesn't handle shared. -- Marco
Jul 07 2013
prev sibling next sibling parent "Tommi" <tommitissari hotmail.com> writes:
On Sunday, 7 July 2013 at 11:59:36 UTC, Marco Leise wrote:
 Am Sun, 07 Jul 2013 13:17:23 +0200
 schrieb "TommiT" <tommitissari hotmail.com>:

 const would have the same effect:
 
 void f(T)(const T var) { ... }
 
 ...but then you can't mutate var.

That doesn't handle shared.

That seems like a compiler bug to me.
Jul 07 2013
prev sibling next sibling parent reply Dmitry Olshansky <dmitry.olsh gmail.com> writes:
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.
 Ie, if called with:
    const int x;
    f(x);
 Then f() should be generated void f(int) rather than void f(const int).

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

-- Dmitry Olshansky
Jul 07 2013
parent Jacob Carlborg <doob me.com> writes:
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
Jul 08 2013
prev sibling next sibling parent "Dicebot" <public dicebot.lv> writes:
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.
Jul 07 2013
prev sibling next sibling parent "Tommi" <tommitissari hotmail.com> writes:
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) ...
Jul 07 2013
prev sibling next sibling parent Manu <turkeyman gmail.com> writes:
--001a1133056ecf260604e0f68cf5
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: quoted-printable

On 7 July 2013 22:31, Dmitry Olshansky <dmitry.olsh gmail.com> wrote:

 06-Jul-2013 05:34, Manu =D0=BF=D0=B8=D1=88=D0=B5=D1=82:

 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). --001a1133056ecf260604e0f68cf5 Content-Type: text/html; charset=UTF-8 Content-Transfer-Encoding: quoted-printable <div dir=3D"ltr">On 7 July 2013 22:31, Dmitry Olshansky <span dir=3D"ltr">&= lt;<a href=3D"mailto:dmitry.olsh gmail.com" target=3D"_blank">dmitry.olsh g= mail.com</a>&gt;</span> wrote:<br><div class=3D"gmail_extra"><div class=3D"= gmail_quote"> <blockquote class=3D"gmail_quote" style=3D"margin:0 0 0 .8ex;border-left:1p= x #ccc solid;padding-left:1ex">06-Jul-2013 05:34, Manu =D0=BF=D0=B8=D1=88= =D0=B5=D1=82:<br> <blockquote class=3D"gmail_quote" style=3D"margin:0 0 0 .8ex;border-left:1p= x #ccc solid;padding-left:1ex"><div class=3D"im"> Okay, so I feel like this should be possible, but I can&#39;t make it work.= ..<br> I want to use template deduction to deduce the argument type, but I want<br=

verbatim type of the argument given.<br> <br></div><div class=3D"im"> I&#39;ve tried: void f(T : Unqual!U, U)(T a) {}<br> and: void f(T)(Unqual!T a) {}<br> </div></blockquote> <br> The thing is that if even if you somehow force your way past IFTI what woul= d be generated is:<br> <br> f!(const int)(int arg);<br> f!(immutable int)(int arg);<br> f!(shared int)(int arg);<br> f!(const shared int)(int arg);<br> <br> Which IMHO falls short of desired goal.<br> Short of using a forwarding thunk (that you don&#39;t like, but if there wa= s force_inline?) we&#39;d have to hack the compiler.</blockquote><div><br><= /div><div style>Hmmm, this is an interesting point.</div><div style>I initi= ally thought this was desirable, it could be useful.</div> <div style>But now that you point it out, I guess the point you are making = is that they will all mangle separately anyway?</div><div style>That seems = problematic, because since all have the same return value and physical argu= ments, how does the compiler choose an overload to call in various circumst= ances?</div> <div style>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).</div=

--001a1133056ecf260604e0f68cf5--
Jul 07 2013
prev sibling next sibling parent "Dicebot" <public dicebot.lv> writes:
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.
Jul 08 2013
prev sibling next sibling parent Martin Nowak <code dawg.eu> writes:
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).

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; }
Jul 08 2013
prev sibling parent Manu <turkeyman gmail.com> writes:
--089e0160c35a1ce76b04e164e8c5
Content-Type: text/plain; charset=UTF-8

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

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 :( --089e0160c35a1ce76b04e164e8c5 Content-Type: text/html; charset=UTF-8 Content-Transfer-Encoding: quoted-printable <div dir=3D"ltr">On 8 July 2013 21:16, Martin Nowak <span dir=3D"ltr">&lt;<= a href=3D"mailto:code dawg.eu" target=3D"_blank">code dawg.eu</a>&gt;</span=
 wrote:<br><div class=3D"gmail_extra"><div class=3D"gmail_quote"><blockquo=

lid;padding-left:1ex"> <div class=3D"im">On 07/06/2013 03:34 AM, Manu wrote:<br> </div><blockquote class=3D"gmail_quote" style=3D"margin:0 0 0 .8ex;border-l= eft:1px #ccc solid;padding-left:1ex"><div class=3D"im"> Okay, so I feel like this should be possible, but I can&#39;t make it work.= ..<br> I want to use template deduction to deduce the argument type, but I want<br=

verbatim type of the argument given.<br> <br> I&#39;ve tried: void f(T : Unqual!U, U)(T a) {}<br> and: void f(T)(Unqual!T a) {}<br> <br></div><div class=3D"im"> Ie, if called with:<br> =C2=A0 =C2=A0const int x;<br> =C2=A0 =C2=A0f(x);<br> Then f() should be generated void f(int) rather than void f(const int).<br> <br> </div></blockquote> I can&#39;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 Templa= te!A. Basically you&#39;d need the inverse of the Template and the type map= ping would need to be bijectiv.<br> <br> What does work though and looks similar is to deduce A from a match of Temp= late!B with Template!A.</blockquote><div><br></div><div style>I&#39;m not s= ure I follow. Can you demonstrate?</div><div><br></div><div><br></div> <blockquote class=3D"gmail_quote" style=3D"margin:0 0 0 .8ex;border-left:1p= x #ccc solid;padding-left:1ex"><div class=3D"im"> <blockquote class=3D"gmail_quote" style=3D"margin:0 0 0 .8ex;border-left:1p= x #ccc solid;padding-left:1ex"> I don&#39;t want a million permutations of the template function for each<b= r> combination of const/immutabe/shared/etc, which especially blows out<br> when the function has 2 or more args.<br> <br> Note: T may only be a primitive type. Obviously const(int*) can never be<br=

</blockquote> <br></div> There is a linker optimization that would get rid of the duplicates.<br> <a href=3D"http://stackoverflow.com/questions/15168924/gcc-clang-merging-fu= nctions-with-identical-instructions-comdat-folding" target=3D"_blank">http:= //stackoverflow.com/<u></u>questions/15168924/gcc-clang-<u></u>merging-func= tions-with-<u></u>identical-instructions-comdat-<u></u>folding</a><br> <br> I came up with &quot;out-of-bound&quot; template instantiations to avoid un= needed instantiations.<br> 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.<br> For example this idiom is useful when you pass additional arguments to your= template, e.g. __FILE__ and __LINE__.<br> <br> void _f(T)(T a) {}<br> void f(T)(T a) { return _f!(Unqual!T)(a); }<br> <br> template _f(CommonArgs) { enum _f =3D foo!CommonArgs; }<br> template f(CommonArgs, MoreArgs) { static assert(bar!MoreArgs); enum f =3D = _f!CommonArgs; }<br> </blockquote></div><br></div><div class=3D"gmail_extra" style>I really hate= relying on linker optimisations to clean up mess like this, which simply s= houldn&#39;t exist in the first place.</div><div class=3D"gmail_extra" styl= e> 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&#39;t THAT much slower/bigger by nature. But t= here&#39;s a big different between 10 times slower and 100 times slower. Li= kewise, there&#39;s also a big difference between twice as big, and 10 time= s as big. Depending on the optimiser to eliminate this sort of duplication = tends your debug code towards the latter.</div> <div class=3D"gmail_extra" style><br></div><div class=3D"gmail_extra" style=
At my prior company, we were very proud that our debug build still ran at =

s or less, which means you can&#39;t practically test AND debug your code. = It&#39;s very hard to reveal the bug you&#39;re chasing if you can&#39;t ph= ysically test the build.</div> <div class=3D"gmail_extra" style>Every new person we employed was amazed, a= nd commented on this. It was without doubt, a strategic advantage for our c= ompany. And the reason we succeeded to this end, was simply because we bann= ed C++ (well, most of it) :/</div> <div class=3D"gmail_extra" style>D makes templates so convenient, one can i= magine the typical situation might even be worse than typical C++. So inste= ad, D needs to take the opportunity to offer tools to allow the programmer = to express what they actually want, rather than generating copious bloat, a= nd expecting optimisation passes to clean it up.</div> <div class=3D"gmail_extra" style><br></div><div class=3D"gmail_extra" style=
Forwarding to secondary functions like this is really horrible. So now my =

want to do in the first place) requires that I mutilate my code. What are t= he sensible naming conventions for this scheme? Does this really improve re= adability? What about find-in-files/go-to-definition?</div> <div class=3D"gmail_extra" style>I&#39;m sure we can do better than this...= actually, we must. I won&#39;t accept this. Bloat should be factored out b= y design. It&#39;s not something that should be ignored, and then attempted= to clean up later.</div> <div class=3D"gmail_extra" style><br></div><div class=3D"gmail_extra" style=
So I&#39;m back where I started :/</div><div class=3D"gmail_extra" style>A=

n.</div> <div class=3D"gmail_extra" style><br></div><div class=3D"gmail_extra" style=
I want this for example:</div><div class=3D"gmail_extra" style>=C2=A0 void=

iv class=3D"gmail_extra" style> When called with:</div><div class=3D"gmail_extra" style>=C2=A0 int x;</div>= <div class=3D"gmail_extra" style>=C2=A0 const(int) cx;</div><div class=3D"g= mail_extra" style>=C2=A0 immutable(int) ix;</div><div class=3D"gmail_extra"= style>=C2=A0 shared(int) sx;</div> <div class=3D"gmail_extra" style><br></div><div class=3D"gmail_extra" style=
=C2=A0 f(x);</div><div class=3D"gmail_extra" style>=C2=A0 f(cx);</div><div=

style>=C2=A0 f(sx);</div><div class=3D"gmail_extra" style> <br></div><div class=3D"gmail_extra" style>All calls deduce the template in= stantiation: void f(int)(int arg);</div><div class=3D"gmail_extra" style><b= r></div><div class=3D"gmail_extra" style>I can see why my example syntax do= esn&#39;t work. The &#39;T&#39; in the argument list is actually the invers= e of what I want, like you say.</div> <div class=3D"gmail_extra" style>But I&#39;m sure there are tweaks on the e= xpression that could possibly make sense somehow.</div><div class=3D"gmail_= extra" style>Basically, is it possible? Is there another approach that coul= d produce the same outcome; that is, having more control over the template = argument deduction, and consequently, the resulting template instantiation?= </div> <div class=3D"gmail_extra" style><br></div><div class=3D"gmail_extra" style=
Some creative thought can surely crack this nut. I think this is a severe =

f the heavy weights have commented on this topic :(</div> </div> --089e0160c35a1ce76b04e164e8c5--
Jul 13 2013