May 02, 2022

On Monday, 2 May 2022 at 16:29:05 UTC, Loara wrote:

>

On Sunday, 1 May 2022 at 03:57:12 UTC, Elfstone wrote:

>

[...]

Template deduction for aliased function parameter is a very tricky argument and it's not so simple to handle in certain cases. Consider for example this code:

    template MyAlias(T){
      alias MyAlias = int;
    }

    T simp(T)(MyAlias!T val){
      return T.init;
    }

    int main(){
      simp(3);//Impossible to deduce T
      simp( cast(MyAlias!string) 4);//Also invalid since MyAlias!string is exactly int
      simp!string(4);//Ok, no parameter deduction
    }

I don't really see what your example is trying to show. This also doesn't work,
and in my mind should be equivalent:

T simp(T)(int val) {
    return T.init;
}

int main() {
    simp(3);//Impossible to deduce T
}
May 02, 2022

On Monday, 2 May 2022 at 16:29:05 UTC, Loara wrote:

>

Template deduction for aliased function parameter is a very tricky argument and it's not so simple to handle in certain cases. Consider for example this code:

    template MyAlias(T){
      alias MyAlias = int;
    }

    T simp(T)(MyAlias!T val){
      return T.init;
    }

    int main(){
      simp(3);//Impossible to deduce T

Why? That's the issue. It is very possible to deduce T here. Compiler just isn't trying. The function takes an int. Doesn't take a rocket scientist to figure that one out.

>
  simp( cast(MyAlias!string) 4);//Also invalid since MyAlias!string is exactly int

Yes, invalid, as well it should be.

>
  simp!string(4);//Ok, no parameter deduction
}

No issue here.

>

Instead to use aliases it's better (both in D and in C++) to use constraints/concepts.

No. It would be better if compiler didn't play stupid here. I shouldn't have to write 50+ more lines boilerplate for what the compiler should be able to figure out. I might as well forego the templates and just write explicit overloads. At which point I would question why use templates at all.

May 02, 2022
On 5/2/22 12:17, Stanislav Blinov wrote:
> On Monday, 2 May 2022 at 16:29:05 UTC, Loara wrote:
>
>> Template deduction for aliased function parameter is a very tricky
>> argument and it's not so simple to handle in certain cases. Consider
>> for example this code:
>>
>> ```d
>>     template MyAlias(T){
>>       alias MyAlias = int;
>>     }
>>
>>     T simp(T)(MyAlias!T val){
>>       return T.init;
>>     }
>>
>>     int main(){
>>       simp(3);//Impossible to deduce T
>
> Why? That's the issue. It is very possible to deduce T here. Compiler
> just isn't trying.

That's fine because D does not promise to solve such problems. It follows simple deduction rules.

> The function takes an int.

How would the solution be? Wouldn't the compiler have to parse all accessible template bodies to figure out which ones fit? Imagine the following two other templates:

template YourAlias(T) {
  alias YourAlias = int;  // Is it this one?
}

template HerAlias(T) {
  // ...
  alias HerAlias = HisAlias!SomeNameInThisScope;  // Or thi?
}

The compiler would have to solve this problem by digging into HisAlias's SomeNameInThisScope instantiation as well. As far as know, the D language does not work that way. Prolog and friends perhaps?

> Doesn't take a rocket
> scientist to figure that one out.

I think this is one of those cases where it is easier for a human. Although, I think I would have difficulty if there were more than one template parameter.

> I might as well forego the templates and
> just write explicit overloads. At which point I would question why use
> templates at all.

Templates allow single implementations to work for many types, manifest constants, aliases, etc. I wouldn't want to write (or mix-in?) sort() for MyType. Templates are wonderful and their implementation in D is refreshing.

Ali

May 02, 2022
On 02.05.22 21:17, Stanislav Blinov wrote:
> On Monday, 2 May 2022 at 16:29:05 UTC, Loara wrote:
[...]
>> ```d
>>     template MyAlias(T){
>>       alias MyAlias = int;
>>     }
>>
>>     T simp(T)(MyAlias!T val){
>>       return T.init;
>>     }
>>
>>     int main(){
>>       simp(3);//Impossible to deduce T
> 
> Why? That's the issue. It is very possible to deduce T here. Compiler just isn't trying. The function takes an int. Doesn't take a rocket scientist to figure that one out.

I take it your answer is that T must be int. But that's nonsense. MyAlias maps all types to int. It's not a bijection, you can't turn it around.
May 02, 2022
On Monday, 2 May 2022 at 20:08:48 UTC, Ali Çehreli wrote:
> On 5/2/22 12:17, Stanislav Blinov wrote:
> > On Monday, 2 May 2022 at 16:29:05 UTC, Loara wrote:
> >
> >> Template deduction for aliased function parameter is a very
> tricky
> >> argument and it's not so simple to handle in certain cases.
> Consider
> >> for example this code:
> >>
> >> ```d
> >>     template MyAlias(T){
> >>       alias MyAlias = int;
> >>     }
> >>
> >>     T simp(T)(MyAlias!T val){
> >>       return T.init;
> >>     }
> >>
> >>     int main(){
> >>       simp(3);//Impossible to deduce T
> >
> > Why? That's the issue. It is very possible to deduce T here.
> Compiler
> > just isn't trying.
>
> That's fine because D does not promise to solve such problems. It follows simple deduction rules.

Words, dear guru. Words have a meaning. It is very possible to deduce here (note the premise). D just isn't trying. That's what I said. You can say "it doesn't promise". Doesn't exactly change the meaning, does it? :)

> > The function takes an int.
>
> How would the solution be? Wouldn't the compiler have to parse all accessible template bodies to figure out which ones fit?

Err... yes? That's what it *is* doing already, for all templates.

> Imagine the following two other templates:
>
> template YourAlias(T) {
>   alias YourAlias = int;  // Is it this one?
> }
>
> template HerAlias(T) {
>   // ...
>   alias HerAlias = HisAlias!SomeNameInThisScope;  // Or thi?
> }

No. HerAlias and YourAlias are different symbols.

> The compiler would have to solve this problem by digging into HisAlias's SomeNameInThisScope instantiation as well. As far as know, the D language does not work that way. Prolog and friends perhaps?

Nope. MyAlias is an alias. A template alias, but an alias nonetheless. It should be resolved prior to trying the overloads.

> > Doesn't take a rocket
> > scientist to figure that one out.
>
> I think this is one of those cases where it is easier for a human. Although, I think I would have difficulty if there were more than one template parameter.

That's what we have compilers for.

> > I might as well forego the templates and
> > just write explicit overloads. At which point I would
> question why use
> > templates at all.
>
> Templates allow single implementations to work for many types, manifest constants, aliases, etc. I wouldn't want to write (or mix-in?) sort() for MyType. Templates are wonderful and their implementation in D is refreshing.

It is, until is isn't. Question du jeour is one of those.


May 02, 2022
On Monday, 2 May 2022 at 20:16:04 UTC, ag0aep6g wrote:
> On 02.05.22 21:17, Stanislav Blinov wrote:
>> On Monday, 2 May 2022 at 16:29:05 UTC, Loara wrote:
> [...]
>>> ```d
>>>     template MyAlias(T){
>>>       alias MyAlias = int;
>>>     }
>>>
>>>     T simp(T)(MyAlias!T val){
>>>       return T.init;
>>>     }
>>>
>>>     int main(){
>>>       simp(3);//Impossible to deduce T
>> 
>> Why? That's the issue. It is very possible to deduce T here. Compiler just isn't trying. The function takes an int. Doesn't take a rocket scientist to figure that one out.
>
> I take it your answer is that T must be int. But that's nonsense. MyAlias maps all types to int. It's not a bijection, you can't turn it around.

That's not my answer. And it is nonsense, because my answer is - what T is irrelevant, MyAlias maps *all* types to int. Therefore `simp` takes an int, which is what the caller is passing.
May 02, 2022

On Monday, 2 May 2022 at 19:17:19 UTC, Stanislav Blinov wrote:

>

On Monday, 2 May 2022 at 16:29:05 UTC, Loara wrote:

>

Template deduction for aliased function parameter is a very tricky argument and it's not so simple to handle in certain cases. Consider for example this code:

    template MyAlias(T){
      alias MyAlias = int;
    }

    T simp(T)(MyAlias!T val){
      return T.init;
    }

    int main(){
      simp(3);//Impossible to deduce T

Why? That's the issue. It is very possible to deduce T here. Compiler just isn't trying. The function takes an int. Doesn't take a rocket scientist to figure that one out.

Maybe I am being silly, but it isn't possible to determine T here. Independent of what T is the input parameter would be an int (which the compiler can't see but we can) but the output depends on T which can't be deduced.

May 03, 2022
On 02.05.22 22:47, Stanislav Blinov wrote:
> On Monday, 2 May 2022 at 20:16:04 UTC, ag0aep6g wrote:
>> On 02.05.22 21:17, Stanislav Blinov wrote:
>>> On Monday, 2 May 2022 at 16:29:05 UTC, Loara wrote:
>> [...]
>>>> ```d
>>>>     template MyAlias(T){
>>>>       alias MyAlias = int;
>>>>     }
>>>>
>>>>     T simp(T)(MyAlias!T val){
>>>>       return T.init;
>>>>     }
>>>>
>>>>     int main(){
>>>>       simp(3);//Impossible to deduce T
[...]
> That's not my answer. And it is nonsense, because my answer is - what T is irrelevant, MyAlias maps *all* types to int. Therefore `simp` takes an int, which is what the caller is passing.

And what does it return?
May 03, 2022

On Monday, 2 May 2022 at 22:01:51 UTC, ag0aep6g wrote:

>

On 02.05.22 22:47, Stanislav Blinov wrote:

>

On Monday, 2 May 2022 at 20:16:04 UTC, ag0aep6g wrote:

>

On 02.05.22 21:17, Stanislav Blinov wrote:

>

On Monday, 2 May 2022 at 16:29:05 UTC, Loara wrote:
[...]

>
    template MyAlias(T){
      alias MyAlias = int;
    }

    T simp(T)(MyAlias!T val){
      return T.init;
    }

    int main(){
      simp(3);//Impossible to deduce T

[...]

>

That's not my answer. And it is nonsense, because my answer is - what T is irrelevant, MyAlias maps all types to int. Therefore simp takes an int, which is what the caller is passing.

And what does it return?

Perhaps one way could be to assume that the parameter passed is of type aliasTemplate!typeOfVar and see if it helps make sense of the invocation? This would only be done if the parameter's type doesn't directly match the required type nor it is implicitly convertible to it(which can be further constrained by... constraints...)
For example, here:

template MyAlias(T){
      alias MyAlias = int;
    }
    // Please note that I changed code, since this is the only way to get the type with which the template parameter was initialized
    U simp(T:MyAlias!U, U)(auto ref T val){
      return U.init;
    }

    int main(){
      simp(3); // val is inferred to be of type MyAlias!int
      simp(”4”); // val is of type MyAlias!string
      simp!string([4,0]); val is of type MyAlias!(int[])
      MyAlias!float d =45;
      simp(d); // val is inferred to be of type MyAlias!(MyAlias!float) // hopefully though the second MyAlias doesn't have to exist and it can just assume the type to be int
    }
May 03, 2022

On Tuesday, 3 May 2022 at 00:38:34 UTC, Tejas wrote:

>

On Monday, 2 May 2022 at 22:01:51 UTC, ag0aep6g wrote:

>

On 02.05.22 22:47, Stanislav Blinov wrote:

>

On Monday, 2 May 2022 at 20:16:04 UTC, ag0aep6g wrote:

>

On 02.05.22 21:17, Stanislav Blinov wrote:

>

On Monday, 2 May 2022 at 16:29:05 UTC, Loara wrote:
[...]

>
    template MyAlias(T){
      alias MyAlias = int;
    }

    T simp(T)(MyAlias!T val){
      return T.init;
    }

    int main(){
      simp(3);//Impossible to deduce T

[...]

>

That's not my answer. And it is nonsense, because my answer is - what T is irrelevant, MyAlias maps all types to int. Therefore simp takes an int, which is what the caller is passing.

And what does it return?

Perhaps one way could be to assume that the parameter passed is of type aliasTemplate!typeOfVar and see if it helps make sense of the invocation? This would only be done if the parameter's type doesn't directly match the required type nor it is implicitly convertible to it(which can be further constrained by... constraints...)
For example, here:

template MyAlias(T){
      alias MyAlias = int;
    }
    // Please note that I changed code, since this is the only way to get the type with which the template parameter was initialized
    U simp(T:MyAlias!U, U)(auto ref T val){
      return U.init;
    }

    int main(){
      simp(3); // val is inferred to be of type MyAlias!int
      simp(”4”); // val is of type MyAlias!string
      simp!string([4,0]); val is of type MyAlias!(int[])
      MyAlias!float d =45;
      simp(d); // val is inferred to be of type MyAlias!(MyAlias!float) // hopefully though the second MyAlias doesn't have to exist and it can just assume the type to be int
    }

Edit: correcting the code

template MyAlias(T){
      alias MyAlias = int;
    }
    // Please note that I changed code, since this is the only way to get the type with which the template parameter was initialized
    U simp(T:MyAlias!U, U)(auto ref T val){
      return U.init;
    }

    int main(){
      simp(3); // val is inferred to be of type MyAlias!int
      simp(”4”); // val is of type MyAlias!string
      simp([4,0]);// val is of type MyAlias!(int[])
      MyAlias!float d =45;
      simp(d); // val is inferred to be of type MyAlias!(MyAlias!float) // hopefully though the second MyAlias doesn't have to exist and it can just assume the type to be int
    }