Thread overview
Doubt about type Inference on templates
Nov 22, 2023
Antonio
Nov 22, 2023
Paul Backus
Nov 23, 2023
Antonio
November 22, 2023

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, 2023

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, 2023

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!!!