January 04, 2021
On 04.01.21 16:03, jmh530 wrote:
> IMO, this is a better example, even if it's a little more verbose.
> 
> struct Foo(T) {}
> 
> alias Bar(T) = Foo!T;
> 
> void f(T)(Bar!T x) {}
> 
> void main() {
>      auto x = Bar!int();
>      f(x);
> }

To be sure that I'm not missing anything: You just added the temporary `x`, right? I don't think that changes anything. The type of the argument is `Foo!int` in all variations of the code we've seen, including this one. And that type is all that DMD sees when it attempts IFTI of `f`.
January 04, 2021
On Monday, 4 January 2021 at 15:25:13 UTC, Atila Neves wrote:
> On Tuesday, 29 December 2020 at 19:59:56 UTC, Ola Fosheim Grøstad wrote:
>> 1. acknowledgment of the issue
>> 2. acknowledgment of what the issue leads to in terms of inconvenience
>> 3. a forward looking vision for future improvements
>
> Your two #1 points aren't the same - understanding/acknowledging the issue. I think I could have done more to acknowledge it now that you brought it up.

In this case, maybe #1 and #2 are the same. But sometimes people will complain about the "inconvenience" and not drill it down to the real cause in terms of language-mechanics.

A valid response could be "I will look and see if I can find the source of this problem, but I totally see the inconvenience you are experiencing. We will look at this more closely when planning for release X.Y.Z where we do an overhaul of subsystem Q.".

I don't think a process oriented response has to be more concrete than that?




January 04, 2021
On Monday, 4 January 2021 at 15:42:05 UTC, Ola Fosheim Grøstad wrote:
> On Monday, 4 January 2021 at 15:25:13 UTC, Atila Neves wrote:
>> On Tuesday, 29 December 2020 at 19:59:56 UTC, Ola Fosheim Grøstad wrote:
>>> 1. acknowledgment of the issue
>>> 2. acknowledgment of what the issue leads to in terms of inconvenience
>>> 3. a forward looking vision for future improvements
>>
>> Your two #1 points aren't the same - understanding/acknowledging the issue. I think I could have done more to acknowledge it now that you brought it up.
>
> In this case, maybe #1 and #2 are the same. But sometimes people will complain about the "inconvenience" and not drill it down to the real cause in terms of language-mechanics.
>
> A valid response could be "I will look and see if I can find the source of this problem, but I totally see the inconvenience you are experiencing. We will look at this more closely when planning for release X.Y.Z where we do an overhaul of subsystem Q.".
>
> I don't think a process oriented response has to be more concrete than that?

I wasn't a process-oriented answer, nor do I think it should have been. The PR was a change to the compiler with an accompanying DIP. I'm a fan of giving an opinion early to save everyone a lot of work and bother.
January 04, 2021
On Monday, 4 January 2021 at 15:53:44 UTC, Atila Neves wrote:
> I wasn't a process-oriented answer, nor do I think it should have been. The PR was a change to the compiler with an accompanying DIP. I'm a fan of giving an opinion early to save everyone a lot of work and bother.


All management communication about conclusions have a process oriented aspect to them. Do you just want to quickly shut the door completely, or do you want to give people a feeling that their ideas will be remembered in the continuing process of improving the product?

If you cannot grow that feeling, then the incentive to try will be reduce significantly...

January 04, 2021
On Monday, 4 January 2021 at 13:47:17 UTC, Ola Fosheim Grøstad wrote:
> On Monday, 4 January 2021 at 12:35:12 UTC, John Colvin wrote:
>> What's the simplest example that doesn't work and is that simple example just indirection through an alias or is it actually indirection through a template that *when instantiated* turns out to be just an alias?
>
> Indirection through a parametric alias. This is the simplest I have come up with so far:
>
>
>   struct Foo(T) {}
>
>   alias Bar(T) = Foo!T;
>
>   void f(T)(Bar!T x) {}
>
>   void main() {
>     f(Bar!int());
>   }
>
>
> I created a thread for it:
>
> https://forum.dlang.org/post/nxrfrizqdmhzhivxptsb@forum.dlang.org
>
>
>> I have a suspicion that what you're asking for here is the type-inference to have x-ray vision in to uninstantiated templates that works for a few simple cases. Am I wrong?
>
> No, just substitute: "Bar!int" with "Foo!int".
>
>
>> To be clear, a really useful special case can be really useful and worthwhile, but I'm not convinced this is the principled "type system bug" you are saying it is.
>
> Why are you not convinced?
>
> An alias is a short hand. If it is possible to discriminate by the alias and the actual object then that it a semantic problem.

I have a longer reply I'm trying to write, but just to make sure I'm on the right track:

    template Foo(T) {
        alias Foo = T;
    }

    template Q(A : Foo!T, T) {
        pragma(msg, A.stringof, " ", T.stringof);
    }

    alias X = Q!(Foo!int);

in your opinion, this should compile and msg `int int`, yes?

I'm trying to make a really concise example without using IFTI.
January 04, 2021
On Monday, 4 January 2021 at 17:22:55 UTC, John Colvin wrote:
> On Monday, 4 January 2021 at 13:47:17 UTC, Ola Fosheim Grøstad wrote:
>> [...]
>
> I have a longer reply I'm trying to write, but just to make sure I'm on the right track:
>
>     template Foo(T) {
>         alias Foo = T;
>     }
>
>     template Q(A : Foo!T, T) {
>         pragma(msg, A.stringof, " ", T.stringof);
>     }
>
>     alias X = Q!(Foo!int);
>
> in your opinion, this should compile and msg `int int`, yes?
>
> I'm trying to make a really concise example without using IFTI.

and presumably the same for
    alias X = Q!(int);
yes?
January 04, 2021
On Monday, 4 January 2021 at 15:31:02 UTC, ag0aep6g wrote:
> On 04.01.21 16:03, jmh530 wrote:
>> IMO, this is a better example, even if it's a little more verbose.
>> 
>> struct Foo(T) {}
>> 
>> alias Bar(T) = Foo!T;
>> 
>> void f(T)(Bar!T x) {}
>> 
>> void main() {
>>      auto x = Bar!int();
>>      f(x);
>> }
>
> To be sure that I'm not missing anything: You just added the temporary `x`, right? I don't think that changes anything. The type of the argument is `Foo!int` in all variations of the code we've seen, including this one. And that type is all that DMD sees when it attempts IFTI of `f`.

Ah, I see your point above now (mixing up my Bar!ints and Bar!Ts). Yes, that was the only change and not really a substantive change (just my ease of reading).

Your point is basically that a template alias only becomes an actual alias when it has been instantiated. You then note that the deduction process operates in terms of Bar (in that you have to find a T that fits Bar!T to get to an alias of Foo!T). I think part of what is confusing is that the temporary x in my example is a Foo!int and not a Bar!int, which is why the Foo!int can't be passed into f(T)(Bar!T).

I think part of the issue is that many people's mental model would be for f(T)(Bar!T) to get re-writtn as f(T)(Foo!T), which is related to Ola's point with respect to type unification.

But the compiler isn't really doing any re-writing, so much as it sees the Foo!int and does not have the information necessary to determine that a Foo!int should satisfy Bar!T (as you point out). It would need to extract int from Foo!int, then instantiate Bar!T to get Foo!int (which I believe is what the implementation was doing, or something similar).

January 04, 2021
On Monday, 4 January 2021 at 17:24:53 UTC, jmh530 wrote:
> Your point is basically that a template alias only becomes an actual alias when it has been instantiated. You then note that the deduction process operates in terms of Bar (in that you have to find a T that fits Bar!T to get to an alias of Foo!T).

Right.

> I think part of what is confusing is that the temporary x in my example is a Foo!int and not a Bar!int, which is why the Foo!int can't be passed into f(T)(Bar!T).

Well, `x` is both a `Foo!int` and a `Bar!int`. They're the same type. `f(Bar!int())` fails in the same way as `f(Foo!int())` does.

> I think part of the issue is that many people's mental model would be for f(T)(Bar!T) to get re-writtn as f(T)(Foo!T), which is related to Ola's point with respect to type unification.

I think you're hitting the nail on the head here regarding the confusion. Such a rewrite makes intuitive sense, and it would be nice, but it doesn't happen.

> But the compiler isn't really doing any re-writing, so much as it sees the Foo!int and does not have the information necessary to determine that a Foo!int should satisfy Bar!T (as you point out). It would need to extract int from Foo!int, then instantiate Bar!T to get Foo!int (which I believe is what the implementation was doing, or something similar).

The compiler can and does extract `Foo` and `int` from `Foo!int`. Then it compares `Foo` to `Bar` and sees that they're not the same template. Then it gives up. The compiler would need to inspect the template `Bar`, see that it's an alias template that expands to `Foo!T` and then continue with that. I.e., it would need to do the rewrite as you say.
January 04, 2021
On Monday, 4 January 2021 at 17:24:42 UTC, John Colvin wrote:
>> in your opinion, this should compile and msg `int int`, yes?


It does match:

template Q(A : Foo!int) {
        pragma(msg, A.stringof);
}


So in then it should also match Foo!T, yes?


January 04, 2021
On Monday, 4 January 2021 at 17:58:35 UTC, Ola Fosheim Grøstad wrote:
> On Monday, 4 January 2021 at 17:24:42 UTC, John Colvin wrote:
>>> in your opinion, this should compile and msg `int int`, yes?
>
>
> It does match:
>
> template Q(A : Foo!int) {
>         pragma(msg, A.stringof);
> }
>
>
> So in then it should also match Foo!T, yes?

Please also note that it is completely acceptable to put limits on the constraints you are allowed to use on matching in order to get good performance, but it should work for the constraints you do allow.