September 07, 2019
On Friday, 6 September 2019 at 21:05:41 UTC, Daniel Kozak wrote:
> The issue is that your abstract is wrong. You have missed T
> For eg.: you have void templateFunction(TemplateType!T arg) { }
> instead of void templateFunction(T)(TemplateType!T arg) { }

Yes, is was pointed out and acknowledged above.

- Stefanos


September 10, 2019
On Friday, 6 September 2019 at 12:58:33 UTC, Stefanos Baziotis wrote:
> Thanks Mike and jmh530.
>
> [snip]

I'm sure I could find some way to simplify this what's below, but I've just been thinking about Atila's concepts library and it's interaction with this DIP [1]. Removing the concepts-specific part of it, it becomes

void checkFoo(T)()
{
    T t = T.init;
    t.foo();
}

enum isFoo(T) = is(typeof(checkFoo!T));

struct Foo
{
    void foo() {}
}

I'm curious if this DIP is accepted could something like the following work

template Foo_able(T)
    if (isFoo!T)
{
    alias Foo_able = T;
}

void useFoo(T)(auto ref Foo_able!T x) {

}

void main() {
    Foo x;
    useFoo(x);
}

Right now, to get it to work would require writing useFoo!Foo(x) because the Foo is not detected to be a Foo_able!T.

If something like the above works under this DIP, while I grant I don't think that this resolves all of the issues that the concepts library tries to address, I think it would be a win for readability.

The big thing that the concepts library provides over what is above is improved error messages (as of now, it is just a replacement of the template constraint). It tells you why the argument does not fit. It seems like if the alias is transformed to something like below, still using the concepts library, then it you would still be able to get the improved error messages. You wouldn't need to apply the models UDA to the struct in this case in order to get the good error messages.

template Foo_able(T)
{
    static assert(models!(T, isFoo));
    alias Foo_able = T;
}

[1] https://github.com/atilaneves/concepts
September 10, 2019
On Tuesday, 10 September 2019 at 14:06:10 UTC, jmh530 wrote:
> On Friday, 6 September 2019 at 12:58:33 UTC, Stefanos Baziotis wrote:
>> Thanks Mike and jmh530.
>>
>> [snip]
>
> I'm sure I could find some way to simplify this what's below, but I've just been thinking about Atila's concepts library and it's interaction with this DIP [1]. Removing the concepts-specific part of it, it becomes
>
> void checkFoo(T)()
> {
>     T t = T.init;
>     t.foo();
> }
>
> enum isFoo(T) = is(typeof(checkFoo!T));
>
> struct Foo
> {
>     void foo() {}
> }
>
> I'm curious if this DIP is accepted could something like the following work
>
> template Foo_able(T)
>     if (isFoo!T)
> {
>     alias Foo_able = T;
> }
>
> void useFoo(T)(auto ref Foo_able!T x) {
>
> }
>
> void main() {
>     Foo x;
>     useFoo(x);
> }
>
> Right now, to get it to work would require writing useFoo!Foo(x) because the Foo is not detected to be a Foo_able!T.
>
> If something like the above works under this DIP, while I grant I don't think that this resolves all of the issues that the concepts library tries to address, I think it would be a win for readability.
>

TBH, I did not understand completely the code. From what I can tell,
this DIP doesn't have connection with the code above because
there's no alias. But this might be an oversimplification and
I might have missed something.

>
> The big thing that the concepts library provides over what is above is improved error messages (as of now, it is just a replacement of the template constraint). It tells you why the argument does not fit. It seems like if the alias is transformed to something like below, still using the concepts library, then it you would still be able to get the improved error messages. You wouldn't need to apply the models UDA to the struct in this case in order to get the good error messages.
>
> template Foo_able(T)
> {
>     static assert(models!(T, isFoo));
>     alias Foo_able = T;
> }

Again, sorry for not understanding. I'm not familiar with the concepts library.
From what I can tell, this again has no connection with the DIP. The alias
is not a template alias and it's not used as a function argument.

- Stefanos


September 10, 2019
On Tuesday, 10 September 2019 at 21:48:33 UTC, Stefanos Baziotis wrote:
> [snip]
>>
>
> TBH, I did not understand completely the code. From what I can tell,
> this DIP doesn't have connection with the code above because
> there's no alias. But this might be an oversimplification and
> I might have missed something.
>

What do you mean there is no alias? This is an alias:

template Foo_able(T)
    if (isFoo!T)
{
    alias Foo_able = T;
}

It's using the explicit template syntax. The template documentation [1] has "template TFoo(T) { alias Ptr = T*; }" as an example. This is very similar except it has a template constraint and I use an eponymous template. Without the template constraint it is template Foo_able(T) { alias Foo_able = T; }

For your other point, if above is a template alias, then the other must also (just adding in a static assert). Regardless, it would be used as a function parameter in the useFoo function.

[1] https://dlang.org/spec/template.html
September 11, 2019
On Tuesday, 10 September 2019 at 21:48:33 UTC, Stefanos Baziotis wrote:
> [snip]

Here is a simpler example:

import std.traits : isNumeric;

template Foo(T)
    if (isNumeric!T)
{
    alias Foo = T;
}

void useFoo(T)(Foo!T x) {

}

void main() {
    int x;
    useFoo!int(x);
    useFoo(x); //error currently, will it compile with this DIP?
}


September 11, 2019
On Wednesday, 11 September 2019 at 00:35:26 UTC, jmh530 wrote:
> On Tuesday, 10 September 2019 at 21:48:33 UTC, Stefanos Baziotis wrote:
>> [snip]
>
> Here is a simpler example:
>
> import std.traits : isNumeric;
>
> template Foo(T)
>     if (isNumeric!T)
> {
>     alias Foo = T;
> }
>
> void useFoo(T)(Foo!T x) {
>
> }
>
> void main() {
>     int x;
>     useFoo!int(x);
>     useFoo(x); //error currently, will it compile with this DIP?
> }

Thanks, that is clearer. And I understand the reasoning now.
Yes, it should. As far as I can tell, the draft
PR had a more complicated test case / example than this.
You can check it here [1]

[1] https://github.com/dlang/dmd/pull/9778/files#diff-f1fd9ecb820a6d8a95c2ba9675ce5071R34

September 11, 2019
On Wednesday, 11 September 2019 at 01:39:22 UTC, Stefanos Baziotis wrote:
> Yes, it should. As far as I can tell, the draft
> PR had a more complicated test case / example than this.

Actually, just checked on the draft PR, it doesn't work.

First of all, sorry for the fact that I have forgotten a lot of things
regarding the implementation and the DIP.
This implementation and DIP were authored 4 months ago.

As I understand it, because this PR and DIP handle template alias, they don't handle templates (that may somehow resolve to aliases). That may be an omission or
it may be out of scope of this DIP.

Let me try to make this more clear. The first test case in the PR is:

struct TestType(T, Q) { }

alias TestAlias(T, Q) = TestType!(T, Q);
static void testFunction(T, Q)(TestAlias!(T, Q) arg) { }

void main()
{
    TestAlias!(int, float) testObj;  // This resolves to TestType
    testFunction(testObj);  // testObj is passed with type TestType
}

So, right now, the _actual_ argument has the resolved type but the _formal_
argument (i.e. `arg`) has not. It has TestAlias. And so, we try to replace
this formal argument type with the actual type.

One could say that your example looks similar. We want to resolve the formal argument `x` to its actual type, but we're stuck in the Foo!T. The problem
is that `Foo` is not an alias. It's a template. And with a contract in it.

To me, it _seems_ like a  similar logic, but the implementation and the semantic details (which also implies - the formal specification in the DIP) are quite
different and would require major additions.

We may need a separate DIP for this.

Nonetheless, thank you very much for pointing it out! Either it's part of this
DIP or not.

- Stefanos
September 11, 2019
On 11.09.19 04:02, Stefanos Baziotis wrote:
> As I understand it, because this PR and DIP handle template alias, they don't handle templates (that may somehow resolve to aliases).

A "template alias" is nothing but a (simple) template that resolves to an alias.

This:
    alias Foo(T) = ...;
is just short for this:
    template Foo(T) { alias Foo = T; }
They are exactly the same thing to the compiler.

You can say that the DIP only applies to the simplest templates, i.e. no constraints, no specializations, no conditionals in the template, etc. But distinguishing between "template alias" and "template that resolves to an alias" makes no sense.

By the way, the proper term is "alias template".
https://dlang.org/spec/template.html#alias-template
September 11, 2019
On Wednesday, 11 September 2019 at 02:02:58 UTC, Stefanos Baziotis wrote:
> [snip]
>
> Nonetheless, thank you very much for pointing it out! Either it's part of this
> DIP or not.
>
> - Stefanos

No problem. ag0aep6g's comments above are also pretty spot on.

I'm not a compiler expert or anything, so I didn't go through every little piece of the DIP initially in order to try to grok how it worked. I don't have a good sense of how the compiler currently resolves templates, so trying to understand how it worked in this specific case seemed like a big hill to climb.

The reason why I was talking about the explicit template syntax is because it provides a lot of flexibility.

When talking about Atila's concepts library above, the thing that is in the back of my mind is something like isInputRange (he provides an example in the Readme.md). One issue with passing an input range to a lot of phobos functions is that if you pass something that isn't an input range the error message isn't specific about why it isn't an input range. For instance, did you forget to define popFront? The concepts library helps provide better error messages in this case. However, it currently requires you to use @models at the top of the struct in order to check this information. This requires the user to put models UDA before their own struct, rather than this happening at the point of the function. If we were able to do something like below, then the user does not need to put it on their own structs. I think that would make the concepts library much more powerful.

template InputRange(T) {
    import concepts: models, isInputRange;
    static assert(models!(Foo, isInputRange));
    alias InputRange = T;
}

void useInputRange(T)(InputRange!T foo) {

}

September 11, 2019
On Wednesday, 11 September 2019 at 05:32:22 UTC, ag0aep6g wrote:
> A "template alias" is nothing but a (simple) template that resolves to an alias.
>
> This:
>     alias Foo(T) = ...;
> is just short for this:
>     template Foo(T) { alias Foo = T; }
> They are exactly the same thing to the compiler.

We should be more precise here. 2 things that are semantically the same
might not be the same for the compiler (and the compiler's job is to handle
them as the same). A trivial example is this:
```
alias my_int = int;

my_int x;
...
```

my_int and int are semantically exactly the same, but to the compiler they're
not. The compiler has to do work to handle them as the same.

I'm not saying that in your example they are or not, because I don't know / remember. You might do though.
But this is an important distinction. As far as I remember, they're
not handled as the same and I wouldn't think that they're handled the same
as well.

As another point, and this is the only important thing to a DIP (aka formal
specification): 2 things might be semantically the same but not formally
the same. The example above is in that category. The one is an alias declaration
and the other a built-in type. But the specification should say that they
should be handled the same.

As far as I'm concerned, your example is a template declaration that resolves
to an alias declaration, which is different from an alias declaration.

- Stefanos