Jump to page: 1 2
Thread overview
Non-consistent implicit function template specializations
Aug 17, 2021
Rekel
Aug 17, 2021
Mike Parker
Aug 17, 2021
Rekel
Aug 17, 2021
Mike Parker
Aug 17, 2021
Rekel
Aug 17, 2021
Rekel
Aug 17, 2021
Rekel
Aug 18, 2021
Rekel
Aug 17, 2021
Ali Çehreli
Aug 18, 2021
Rekel
Aug 18, 2021
Paul Backus
Aug 18, 2021
Rekel
Aug 18, 2021
Ali Çehreli
August 17, 2021

When using implicit function templates, identical specialization yield different results.
Example:

template TFoo(T)        { void foo(){writeln("1");} } // #1
template TFoo(T : T[])  { void foo(){writeln("2");} } // #2

void foo(T)(){
	writeln("1");
}

void foo(T : T[])(){
	writeln("1");
}

void main(string[] args) { // Works
	TFoo!(int).foo();            // "1"
	TFoo!(double[]).foo();       // "2"
	foo!(int)();            // "1"
	foo!(double[])();       // "1" !
}

I'm fairly certain the last call should yield "2", yet it does not.
Should I submit a bugreport? And will that even help? There's even 'NEW' bugs from 2016 :'c


Interestingly enough, it seems I've made a previous thread about this in January (https://forum.dlang.org/post/zudtiruaxdfdwcjennmr@forum.dlang.org), though in it I state TFoo!(uint[]) yields the array version, which as can be seen from the example above, is not or no longer true.
Sadly I'm having issues with template arguments more often (https://forum.dlang.org/post/xkgpheuhohbffzgdbqhb@forum.dlang.org)
And I sadly don't see any improvement to this happening any time in the future. Even bugs don't seem to get fixed in any timely manner (Not meant as an insult, just being realistic :/).

August 17, 2021

On Tuesday, 17 August 2021 at 09:59:53 UTC, Rekel wrote:

>

When using implicit function templates, identical specialization yield different results.
Example:

template TFoo(T)        { void foo(){writeln("1");} } // #1
template TFoo(T : T[])  { void foo(){writeln("2");} } // #2

void foo(T)(){
	writeln("1");
}

void foo(T : T[])(){
	writeln("1");
}

void main(string[] args) { // Works
	TFoo!(int).foo();            // "1"
	TFoo!(double[]).foo();       // "2"
	foo!(int)();            // "1"
	foo!(double[])();       // "1" !
}

I'm fairly certain the last call should yield "2", yet it does not.

The error is in your code. Both of your foo templates are implemented to print "1". Change the second one to print "2" and you will see the desired output.

At any rate, to specialize on arrays you should generally be using something like T : U[], U. Ditto for pointers: T : U*, U.

August 17, 2021

On Tuesday, 17 August 2021 at 09:59:53 UTC, Rekel wrote:

>

time in the future. Even bugs don't seem to get fixed in any timely manner (Not meant as an insult, just being realistic :/).

We do have a paid Issue/Pull-Request manager now (Razvan Nitu), and he's prioritizing issues for strike teams composed of volunteers willing to fix them. If you find a specific bug that is a blocker or a major headache, make a post about it here in the forums.

Sometimes, the reason a bug hasn't been fixed is simply that it hasn't caught the attention of the right person. With Razvan in place, it's more likely such issues will be resolved, or at least moved up on the priority list, if you let him know about them. A forum post is an easy way to do that while also bringing it to the attention of others who may be looking for something to work on.

August 17, 2021

On Tuesday, 17 August 2021 at 10:14:07 UTC, Mike Parker wrote:

>

The error is in your code. Both of your foo templates are implemented to print "1". Change the second one to print "2" and you will see the desired output.

I keep managing to disappoint myself greatly... this is absurd, so sorry.

August 17, 2021

On Tuesday, 17 August 2021 at 10:21:39 UTC, Mike Parker wrote:

>

We do have a paid Issue/Pull-Request manager now (Razvan Nitu), and he's prioritizing issues for strike teams composed of volunteers willing to fix them. If you find a specific bug that is a blocker or a major headache, make a post about it here in the forums.

Sometimes, the reason a bug hasn't been fixed is simply that it hasn't caught the attention of the right person. With Razvan in place, it's more likely such issues will be resolved, or at least moved up on the priority list, if you let him know about them. A forum post is an easy way to do that while also bringing it to the attention of others who may be looking for something to work on.

That's great to hear :), I'll keep it in mind.

August 17, 2021

As my post was not the actual cause of my issue (my apology for the mistake), I think I have found the actual reason I'm currently having problems.
This seems to be related to a (seeming, I might be wrong) inability to specialize over both 1d and 2d arrays separately. (If constraining the length to values.)

This brings me to 2 questions.

  1. How does one specialize a template for both 1d and 2d arrays at the same time?
  2. Are there any plans to rework templates? like:
  • Making template TFoo(T : T[]) illegal. This makes little sense to me however I look at it, and as several people have advised against it it's confusing it's in the docs. (21.4.1)
  • Changing the way priorities are set using specializations in general, to make them less pitfall-y.
  • Allow for 2+d length specification. At the moment T[][L] works while T[L][L] does not seem to.
void foo(T)(T a){...}

void foo(T:U[L], uint L)(T a){...}
void foo(T:U[L][L], uint L)(T a){...} // Never matched
void foo(T:U[L], U:V[L], V uint L)(T a){...} // Never matched (alternatively)

// Alternative workaround, very cluttery but with more control.
void foo(T)(T a) if(!is(typeof(a[0]))&&!is(typeof(a[0][0]))) {...}
void foo(T, uint L)(T[L] a) if(!is(typeof(a[0]))){...}
void foo(T, uint L)(T[L][L] a) {...} // Still does not work.
void foo(T, unit L(T[][L] a) {static foreach(i;0..L) assert(a[i].length==L); ...} // Will (generally) work but may include runtime checking & is generally much less preferrable.

// Should work with
void main(string[] args) {
	foo([[1],[2]]);
	foo([1,2]);
	foo(1);
}
void foo(L, T, uint S)(L l, T[S] r){
	writeln("foo");
}

void bar(L, R:T[S], T, uint S)(L l, R r){
	writeln("bar");
}

void main(string[] args) {
	foo(1, [1,2,3,4]); // "foo"
	bar(1, [1,2,3,4]); // "cannot deduce function"
}

I'm actually still not sure why this shouldn't work, but changing bar to foo isn't too difficult. (though it's more preferrable to work regardless, it currently feels like a pitfall)


Not sure if I'm asking the right questions, hope it's not of nuisance.

  • Rekel
August 17, 2021

On 8/17/21 10:20 AM, Rekel wrote:

>

As my post was not the actual cause of my issue (my apology for the mistake), I think I have found the actual reason I'm currently having problems.
This seems to be related to a (seeming, I might be wrong) inability to specialize over both 1d and 2d arrays separately. (If constraining the length to values.)

This brings me to 2 questions.

  1. How does one specialize a template for both 1d and 2d arrays at the same time?
  2. Are there any plans to rework templates? like:
  • Making template TFoo(T : T[]) illegal. This makes little sense to me however I look at it, and as several people have advised against it it's confusing it's in the docs. (21.4.1)
  • Changing the way priorities are set using specializations in general, to make them less pitfall-y.
  • Allow for 2+d length specification. At the moment T[][L] works while T[L][L] does not seem to.

You should try out things individually to see if they at least work.

>
void foo(T)(T a){...}

void foo(T:U[L], uint L)(T a){...}

This is an invalid specification, what is U? Did you mean:

void foo(T: U[L], U, uint L)(T a) {...}

>

void foo(T:U[L][L], uint L)(T a){...} // Never matched

Apart from another missing U, this is only a SQUARE 2d-array (both dimensions the same), your example below only calls with a 1x2 array.

>

void foo(T:U[L], U:V[L], V uint L)(T a){...} // Never matched (alternatively)

I don't think you need this, and I had to comment it out, or the compiler wouldn't build.

>

// Should work with
void main(string[] args) {
    foo([[1],[2]]);
    foo([1,2]);
    foo(1);
}

All these are calling with array literals, which default to dynamic arrays, not static arrays.

-Steve

August 17, 2021

On Tuesday, 17 August 2021 at 16:24:38 UTC, Steven Schveighoffer wrote:

> >

void foo(T:U[L], uint L)(T a){...}

This is an invalid specification, what is U? Did you mean:

Yes, sorry typo in the forum.

>

void foo(T: U[L], U, uint L)(T a) {...}

>

void foo(T:U[L][L], uint L)(T a){...} // Never matched

Apart from another missing U, this is only a SQUARE 2d-array (both dimensions the same), your example below only calls with a 1x2 array.

Again, sorry a typo, calling with [[1,2],[3,4]].

> >

void foo(T:U[L], U:V[L], V uint L)(T a){...} // Never matched (alternatively)

I don't think you need this, and I had to comment it out, or the compiler wouldn't build.

That is correct, it's equivalent thus causes 2 matches.

>

All these are calling with array literals, which default to dynamic arrays, not static arrays.

I realise that is their default, though in this scenario they should (I believe) be used as static arrays. (This works for me in any case)

August 17, 2021

On 8/17/21 2:07 PM, Rekel wrote:

>

On Tuesday, 17 August 2021 at 16:24:38 UTC, Steven Schveighoffer wrote:

> >

All these are calling with array literals, which default to dynamic arrays, not static arrays.

I realise that is their default, though in this scenario they should (I believe) be used as static arrays. (This works for me in any case)

According to my tests, it prefers the T version over the static array version. Which leads me to believe that it prefers a dynamic array over a static one. In fact, if I comment out the T version, it doesn't compile. It literally will not pick that specialization, even if it can interpret the literal that way.

which is really bizarre, since if you do it without specializations, but just spelling out all the template components (as in your alternative workaround), it WILL pick that one over a dynamic array one.

-Steve

August 17, 2021
On 8/17/21 2:59 AM, Rekel wrote:

> template TFoo(T)        { void foo(){writeln("1");} } // #1
> template TFoo(T : T[])  { void foo(){writeln("2");} } // #2

I don't have such problems because I am not smart enough to understand that syntax so I don't use it. :) I use template constraints (which have other problems).

import std.traits;
import std.stdio;

template TFoo(T)
if (!isArray!T)
{
  void foo(){
    writeln("not array");
  }
}

template TFoo(T)
if (isArray!T)
{
  void foo(){
    writeln("array");
  }
}

void main() {
  TFoo!(int).foo();
  TFoo!(int[]).foo();
}

If you want 2 dimensional arrays, then you can use

import std.range;

  isArray!T && (isArray!(ElementType!T))

Ali

« First   ‹ Prev
1 2