Thread overview
Doubt about type Inference on templates
Nov 22
Antonio
Nov 23
Antonio
November 22

Just for fun, I'm trying to implement an alternative base library to avoid template/mixin/static/traits code with only one objective: make "intelliSense" code analyzers tasks easier.

I need "Generics"... but D has not generics: I use templates in the "simplest" possible way

I.E.:

interface IIterable(T)
{
  bool empty();
  void popFront();
  T front();
}

IIterable!S toIterable(S)(S[] source)
  => new ArrayIterable!S(source);
IIterable!S filter(S)(IIterable!S source, bool delegate(S item) predicate)
  => new Filter!S(source, predicate);
IIterable!S filter(S)(S[] source, bool delegate(S item) predicate)
  => toIterable(source).filter(predicate);
// ...

Then, in main.d I do

import std.stdio;
void main(){
  [1,2,3,4,5,6].toIterable!int.filter!int(i=>i%2==0).map!int(i=>i*2).toArray.writeln();
}

It works properly... until I remove the !int from the filter method.

main.d(3,38): Error: none of the overloads of template `filter` are callable using argument types `!()(IIterable!int, void)`
iterable.d(21,13):        Candidates are: `filter(S)(IIterable!S source, bool delegate(S item) predicate)`
iterable.d(23,13):                        `filter(S)(S[] source, bool delegate(S item) predicate)`

Basically, it doesn't know witch version of filter to use, because it is inferring i=>i%2==0 is void ?!?!?!

!()(IIterable!int, void)

If I explicitly write (int i)=>i%2==0, it compiles correctly again.

Is it mandatory to explicitly tell that S is int when IIterable!S source is IIterable!int alredy?

November 22

On Wednesday, 22 November 2023 at 17:53:15 UTC, Antonio wrote:

>

Basically, it doesn't know witch version of filter to use, because it is inferring i=>i%2==0 is void ?!?!?!

!()(IIterable!int, void)

If I explicitly write (int i)=>i%2==0, it compiles correctly again.

Is it mandatory to explicitly tell that S is int when IIterable!S source is IIterable!int alredy?

This is a bug/limitation in the compiler. I couldn't find an existing report on issues.dlang.org, so I've reported it myself as issue 24255.

For now, I think the best way to work around it is to specify the type in the lambda, as in (int i) => i%2 == 0.

The reason you see void is that when the compiler cannot figure out the type of a function literal, it treats it as a template function:

static assert(__traits(isTemplate, i => i % 2 == 0));

And for silly historical reasons, when the compiler tries to determine the type of a template, it returns void instead of giving an error:

template example() {}
static assert(is(typeof(example) == void)); // what??
November 23

On Wednesday, 22 November 2023 at 19:37:58 UTC, Paul Backus wrote:

>

This is a bug/limitation in the compiler. I couldn't find an existing report on issues.dlang.org, so I've reported it myself as [issue 24255][1].

Wow: It is a very concise bug example.

I tested with ldc ant it fails too.

>

For now, I think the best way to work around it is to specify the type in the lambda, as in (int i) => i%2 == 0.

agreed

>

The reason you see void is that when the compiler cannot figure out the type of a function literal, it treats it as a template function:

static assert(__traits(isTemplate, i => i % 2 == 0));

And for silly historical reasons, when the compiler tries to determine the type of a template, it returns void instead of giving an error:

template example() {}
static assert(is(typeof(example) == void)); // what??

Thanks Paul!!!