www.digitalmars.com         C & C++   DMDScript  

digitalmars.D - DIP 1023--Resolution of Template Alias Formal Parameters in Template

reply Mike Parker <aldacron gmail.com> writes:
This is the feedback thread for the first round of Community 
Review for DIP 1023, "Resolution of Template Alias Formal 
Parameters in Template Functions":

https://github.com/dlang/DIPs/blob/bf5157d3dc29a591826e22d188448fbc04ca81b2/DIPs/DIP1023.md

All review-related feedback on and discussion of the DIP should 
occur in this thread. The review period will end at 11:59 PM ET 
on September 20, or when I make a post declaring it complete.

At the end of Round 1, if further review is deemed necessary, the 
DIP will be scheduled for another round of Community Review. 
Otherwise, it will be queued for the Final Review and Formal 
Assessment.

Anyone intending to post feedback in this thread is expected to 
be familiar with the reviewer guidelines:

https://github.com/dlang/DIPs/blob/master/docs/guidelines-reviewers.md

Thanks in advance for keeping all discussion on topic.
Sep 06 2019
next sibling parent reply rikki cattermole <rikki cattermole.co.nz> writes:
The D code blocks should have the language set to D (```d ... ```) for 
easier reading.



Your examples in abstract didn't look right.
I ran the second to confirm my suspicion:

onlineapp.d(9): Error: undefined identifier T



Here is the test case in your implementation linked that made me 
understand your intention for the DIP:

```
void main() {
     TestAlias!(int, float) testObj;
     testFunction(testObj);
}

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

Current error:

onlineapp.d(5): Error: template onlineapp.testFunction cannot deduce 
function from argument types !()(TestType!(int, float)), candidates are:
onlineapp.d(10):        onlineapp.testFunction(T, Q)(TestAlias!(T, Q) arg)
Sep 06 2019
parent reply Stefanos Baziotis <sdi1600105 di.uoa.gr> writes:
On Friday, 6 September 2019 at 12:17:11 UTC, rikki cattermole 
wrote:
 The D code blocks should have the language set to D (```d ... 
 ```) for easier reading.
Thanks, I didn't know about that.
 Your examples in abstract didn't look right.
 I ran the second to confirm my suspicion:

 onlineapp.d(9): Error: undefined identifier T
Could you paste the example that gave you this error? Btw, not all examples are compilable.
 Here is the test case in your implementation linked that made 
 me understand your intention for the DIP:

 ```
 void main() {
     TestAlias!(int, float) testObj;
     testFunction(testObj);
 }

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

 Current error:

 onlineapp.d(5): Error: template onlineapp.testFunction cannot 
 deduce function from argument types !()(TestType!(int, float)), 
 candidates are:
 onlineapp.d(10):        onlineapp.testFunction(T, 
 Q)(TestAlias!(T, Q) arg)
Yes, this example shows exactly the intention. Among other things, the DIP proposes that we should not have an error here.
Sep 06 2019
next sibling parent Mike Parker <aldacron gmail.com> writes:
On Friday, 6 September 2019 at 12:27:50 UTC, Stefanos Baziotis 
wrote:


 Thanks, I didn't know about that.
My bad. I should have caught that when I was revising. I don't normally like to push changes to a DIP under review, but anyone who would prefer to see the DIP with proper highlights is located here: https://github.com/dlang/DIPs/blob/840083a91f4c110832c1d0b61008935b277e32db/DIPs/DIP1023.md
Sep 06 2019
prev sibling next sibling parent reply rikki cattermole <rikki cattermole.co.nz> writes:
On 07/09/2019 12:27 AM, Stefanos Baziotis wrote:
 On Friday, 6 September 2019 at 12:17:11 UTC, rikki cattermole wrote:
 The D code blocks should have the language set to D (```d ... ```) for 
 easier reading.
Thanks, I didn't know about that.
 Your examples in abstract didn't look right.
 I ran the second to confirm my suspicion:

 onlineapp.d(9): Error: undefined identifier T
Could you paste the example that gave you this error? Btw, not all examples are compilable.
This one should be since it is stating current behavior. Looks like I got it wrong, its third not second: ``` struct TemplateType(T) { } alias TemplateAlias(T) = TemplateType!T void templateFunction(TemplateAlias!T arg) { } ``` Two errors (missed the first, semicolon missing). So: ``` struct TemplateType(T) { } alias TemplateAlias(T) = TemplateType!T; void templateFunction(T)(TemplateAlias!T arg) { } ```
 Here is the test case in your implementation linked that made me 
 understand your intention for the DIP:

 ```
 void main() {
     TestAlias!(int, float) testObj;
     testFunction(testObj);
 }

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

 Current error:

 onlineapp.d(5): Error: template onlineapp.testFunction cannot deduce 
 function from argument types !()(TestType!(int, float)), candidates are:
 onlineapp.d(10):        onlineapp.testFunction(T, Q)(TestAlias!(T, Q) 
 arg)
Yes, this example shows exactly the intention. Among other things, the DIP proposes that we should not have an error here.
I replied with this so that you had feedback for improving the DIP if other people find it hard to understand.
Sep 06 2019
parent reply Stefanos Baziotis <sdi1600105 di.uoa.gr> writes:
Thanks Mike and jmh530.

On Friday, 6 September 2019 at 12:48:34 UTC, rikki cattermole 
wrote:
 This one should be since it is stating current behavior.

 Looks like I got it wrong, its third not second:

 ```
 struct TemplateType(T) { }
 alias TemplateAlias(T) = TemplateType!T
 void templateFunction(TemplateAlias!T arg) { }
 ```

 Two errors (missed the first, semicolon missing).
 So:

 ```
 struct TemplateType(T) { }
 alias TemplateAlias(T) = TemplateType!T;
 void templateFunction(T)(TemplateAlias!T arg) { }
 ```
Indeed. Thanks, it will be corrected. Do I wait for the next round to do corrections?
 I replied with this so that you had feedback for improving the 
 DIP if other people find it hard to understand.
You mean include this in the DIP? In the "Description" section there's an identical example.
Sep 06 2019
next sibling parent reply rikki cattermole <rikki cattermole.co.nz> writes:
On 07/09/2019 12:58 AM, Stefanos Baziotis wrote:
 Thanks Mike and jmh530.
 
 On Friday, 6 September 2019 at 12:48:34 UTC, rikki cattermole wrote:
 This one should be since it is stating current behavior.

 Looks like I got it wrong, its third not second:

 ```
 struct TemplateType(T) { }
 alias TemplateAlias(T) = TemplateType!T
 void templateFunction(TemplateAlias!T arg) { }
 ```

 Two errors (missed the first, semicolon missing).
 So:

 ```
 struct TemplateType(T) { }
 alias TemplateAlias(T) = TemplateType!T;
 void templateFunction(T)(TemplateAlias!T arg) { }
 ```
Indeed. Thanks, it will be corrected. Do I wait for the next round to do corrections?
Unless Mike says otherwise, yes.
 I replied with this so that you had feedback for improving the DIP if 
 other people find it hard to understand.
You mean include this in the DIP? In the "Description" section there's an identical example.
No. It is for future reference if there is a trend of people finding it hard to follow.
Sep 06 2019
parent Stefanos Baziotis <sdi1600105 di.uoa.gr> writes:
On Friday, 6 September 2019 at 13:10:49 UTC, rikki cattermole 
wrote:
 You mean include this in the DIP? In the "Description" section 
 there's an
 identical example.
No. It is for future reference if there is a trend of people finding it hard to follow.
Ah yes of course, thanks for referencing it.
Sep 06 2019
prev sibling parent reply jmh530 <john.michael.hall gmail.com> writes:
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
Sep 10 2019
parent reply Stefanos Baziotis <sdi1600105 di.uoa.gr> writes:
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
Sep 10 2019
next sibling parent jmh530 <john.michael.hall gmail.com> writes:
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
Sep 10 2019
prev sibling parent reply jmh530 <john.michael.hall gmail.com> writes:
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? }
Sep 10 2019
parent reply Stefanos Baziotis <sdi1600105 di.uoa.gr> writes:
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
Sep 10 2019
parent reply Stefanos Baziotis <sdi1600105 di.uoa.gr> writes:
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
Sep 10 2019
next sibling parent reply ag0aep6g <anonymous example.com> writes:
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
Sep 10 2019
parent reply Stefanos Baziotis <sdi1600105 di.uoa.gr> writes:
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
Sep 11 2019
parent reply ag0aep6g <anonymous example.com> writes:
On 11.09.19 13:49, Stefanos Baziotis wrote:
 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).
Ok, sure. The difference is in syntax. It's the compiler's job to interpret the shorthand variant exactly like the longhand.
 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.
And it might make sense to focus on that difference if you're writing a DIP that changes the meaning of `alias`. But if you're writing a DIP that changes the meaning of `int`, then we expect that is also applies to `my_int`. So unless your DIP states that it changes the meaning of the alias template shorthand syntax, we expect that it also works with the longhand.
 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 far as I understand, you suspect a semantic difference. If that's so, you're simply mistaken.
 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.
I'm not sure what "formally the same" would entail. Syntactically, the two variants are different (obviously). But that's it. Semantically, the shorthand is defined to mean whatever the longhand means [1].
 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.
Syntactically, `template Foo(T) { alias Foo = T; }` is called a "TemplateDeclaration". Semantically, it declares a template. Syntactically, `alias Foo(T) = T;` is called an "AliasDeclaration". Semantically, it also declares a template. It doesn't declare an alias. [1] https://dlang.org/spec/template.html#alias-template
Sep 11 2019
parent reply Stefanos Baziotis <sdi1600105 di.uoa.gr> writes:
On Wednesday, 11 September 2019 at 14:14:31 UTC, ag0aep6g wrote:
 And it might make sense to focus on that difference if you're 
 writing a DIP that changes the meaning of `alias`. But if 
 you're writing a DIP that changes the meaning of `int`, then we 
 expect that is also applies to `my_int`.
It doesn't change the meaning of alias. It changes how an alias declaration / instantiation acts.
 So unless your DIP states that it changes the meaning of the 
 alias template shorthand syntax, we expect that it also works 
 with the longhand.
It does as far as I'm concerned. It always states alias declarations [1] and template alias instantiations with regard to alias declarations. The "longhand" version is not an alias declaration, it is a template declaration.
 As far as I understand, you suspect a semantic difference. If 
 that's so, you're simply mistaken.
Firstly, there are things to consider regarding the handling inside the compiler. Although that has to do with the implementation, which I don't think we should focus on. The thing is, semantics is about what something means. But, regarding formal specifications, there's another important topic. Actually, the most important for this DIP, which is how something is resolved to be a specific semantic entity. The "longhand" and "shorthand" versions are semantically the same, i.e. they correspond to the same semantic entity, but the way one arrives to this entity is different. Meaning, the rules applied. And one should consider that. Otherwise, the burden is left to the compiler implementor.
 I'm not sure what "formally the same" would entail. 
 Syntactically, the two variants are different (obviously). But 
 that's it. Semantically, the shorthand is defined to mean 
 whatever the longhand means [1].
As I said above, in the way I understand it, one thing representing the same with another is not enough. If that was so, this DIP would not even be needed since most of its work is to describe the resolution procedure.
 Syntactically, `template Foo(T) { alias Foo = T; }` is called a 
 "TemplateDeclaration". Semantically, it declares a template.

 Syntactically, `alias Foo(T) = T;` is called an 
 "AliasDeclaration". Semantically, it also declares a template. 
 It doesn't declare an alias.
Yes, but they're different. Again, going to what I said above.
Sep 11 2019
parent reply ag0aep6g <anonymous example.com> writes:
On 11.09.19 17:48, Stefanos Baziotis wrote:
 On Wednesday, 11 September 2019 at 14:14:31 UTC, ag0aep6g wrote:
[...]
 So unless your DIP states that it changes the meaning of the alias 
 template shorthand syntax, we expect that it also works with the 
 longhand.
It does as far as I'm concerned. It always states alias declarations [1] and template alias instantiations with regard to alias declarations. The "longhand" version is not an alias declaration, it is a template declaration.
So you intend to introduce a difference between shorthand and longhand alias templates? That's awful. To me, that would be a reason to reject the DIP. [...]
 Firstly, there are things to consider regarding the handling
 inside the compiler. Although that has to do with
 the implementation, which I don't think we should focus on.
 
 The thing is, semantics is about what something means.
 But, regarding formal specifications, there's another
 important topic. Actually, the most important for this DIP,
 which is how something is resolved to be a specific semantic
 entity.
 The "longhand" and "shorthand" versions are semantically the same,
 i.e. they correspond to the same semantic entity, but the way
 one arrives to this entity is different. Meaning, the rules
 applied.
 And one should consider that. Otherwise, the burden
 is left to the compiler implementor.
If I understand correctly, you're saying that you want to consider ease of implementation in the compiler. That's fine. But: 1) It's not obvious that you're actually simplifying the implementation by restricting the feature to the shorthand syntax. Your prototype implementation seems to work just fine with the longhand syntax. 2) Even if it happens to be easier to implement, you have to weigh that against adding a surprising special case to the language. I don't think it's going to be a net positive.
Sep 11 2019
parent reply Stefanos Baziotis <sdi1600105 di.uoa.gr> writes:
On Wednesday, 11 September 2019 at 17:53:06 UTC, ag0aep6g wrote:
 So you intend to introduce a difference between shorthand and 
 longhand alias templates?
Not necessarily. But let's say I do (as it seems the DIP does currently) for the rest of this and I will discuss the alternative I'm thinking in the end.
 That's awful. To me, that would be a reason to reject the DIP.
Indeed. :/ When I wrote this DIP, I hadn't thought about the long-hand version. That may seem quite naive, but consider that I was quite new to D and the use cases I was presented then were using only the short-hand version. FWIW, this DIP and its use cases / needs were not mine. But I liked the idea and did the authoring.
 If I understand correctly, you're saying that you want to 
 consider ease of implementation in the compiler.
Not necessarily. That would be good but I'm more concerned about the complexity and clarity of the DIP.
 That's fine. But:

 1) It's not obvious that you're actually simplifying the 
 implementation by restricting the feature to the shorthand 
 syntax. Your prototype implementation seems to work just fine 
 with the longhand syntax.
Indeed it's not obvious.
 2) Even if it happens to be easier to implement, you have to 
 weigh that against adding a surprising special case to the 
 language. I don't think it's going to be a net positive.
Indeed. So, the alternative: My first thought is being more high level. That is, currently the DIP is restricted to alias declarations, while we can have the same exact semantic entity using a different type of declaration. This has a lot of subtle details. Can these declarations have a common way of resolution ? If yes, maybe this is too high-level and it results in yet another not-so-formal-but-intuitive description. If no, should we consider each case separately ? How many are they ? How complicated will the DIP be ? And it's not clear whether I will have the time to do this. Tell me what you think. - Stefanos
Sep 11 2019
parent reply ag0aep6g <anonymous example.com> writes:
On 11.09.19 20:29, Stefanos Baziotis wrote:
 So, the alternative:
 My first thought is being more high level.
 That is, currently the DIP is restricted to alias declarations,
 while we can have the same exact semantic entity using a
 different type of declaration. This has a lot of subtle details.
 Can these declarations have a common way of resolution ?
The longhand is a common way. If you base your DIP on the longhand only, then the shorthand follows automatically, because it's defined to do whatever the longhand does. I.e., if your DIP says that this works: template A(T) { alias A = S!T; } /* longhand */ struct S(T) { } void f(T)(A!T arg) { } void main() { f(S!int()); } Then it follows from the existing spec that it also works when A is declared in shorthand style: alias A(T) = S!T; /* shorthand */ The shorthand is defined to be equivalent to the longhand, and the longhand works, so the shorthand also works. You don't even have to mention it in the DIP. It's already in the spec. By the way, the same shorthand/longhand thing applies to function templates. The DIP currently only uses the shorthand, but it should also work with the longhand (and I'd just assume that it does as long as the DIP doesn't explicitly say otherwise).
 If yes, maybe this is too high-level and it results in yet
 another not-so-formal-but-intuitive description.
 If no, should we consider each case separately ? How many are they ?
 How complicated will the DIP be ?
I feel like working on the (concrete) syntax level is too low-level. I think it's obvious that the new feature should be applied after lexing and parsing. You don't want to write your DIP in terms of characters or keywords. To me, it also seems obvious that the new feature should be applied after shorthand and longhand syntaxes have been consolidated. I'd expect that the parser already does this, but I'm not sure. Beyond that, I'm not knowledgeable enough to say when it should happen. If the shorthand/longhand consolidation is not done by the parser, and not in some very early semantics phase either, then that might make things complicated.
 And it's not clear whether I will have the time to do this.
That's perfectly understandable. No one (in their right mind) is going to blame you, if you don't manage to push this all the way. It's a hard problem. The oldest Bugzilla issue for it is over a decade old, with a dozen or so duplicates. Fixing/implementing that kind of issue isn't usually a walk in the park, or someone would already have done it.
Sep 11 2019
parent reply Stefanos Baziotis <sdi1600105 di.uoa.gr> writes:
On Wednesday, 11 September 2019 at 20:46:46 UTC, ag0aep6g wrote:
 The shorthand is defined to be equivalent to the longhand, and 
 the longhand works, so the shorthand also works. You don't even 
 have to mention it in the DIP. It's already in the spec.
I agree, changes have to be done though. Meaning, it should not focus on alias declaration, it should be more general.
 I feel like working on the (concrete) syntax level is too 
 low-level.

 I think it's obvious that the new feature should be applied 
 after lexing and parsing. You don't want to write your DIP in 
 terms of characters or keywords.

 To me, it also seems obvious that the new feature should be 
 applied after shorthand and longhand syntaxes have been 
 consolidated. I'd expect that the parser already does this, but 
 I'm not sure.

 Beyond that, I'm not knowledgeable enough to say when it should 
 happen. If the shorthand/longhand consolidation is not done by 
 the parser, and not in some very early semantics phase either, 
 then that might make things complicated.
It's not the syntactic part the problem, meaning parsing and lexing. It's the rewriting capabilities of templates. Check Description -> New (in bold) in the DIP. _However_, it's obvious that these rewriting problems don't apply only to alias declarations. Actually, they're borrowed from templates. AFAIK, these rewriting capabilities are not as formally described as they could, but it was not the initial intention of this DIP to describe and it won't be now. What I mean is that it seems feasible to describe the resolution pretty much the same way for both long-hand and short-hand.
 And it's not clear whether I will have the time to do this.
That's perfectly understandable. No one (in their right mind) is going to blame you, if you don't manage to push this all the way. It's a hard problem. The oldest Bugzilla issue for it is over a decade old, with a dozen or so duplicates. Fixing/implementing that kind of issue isn't usually a walk in the park, or someone would already have done it.
Indeed, although now it might be possible. When I was experimenting with this, the implementation seemed quite complicated indeed. So, I left it in a draft stage where I hope will be a good starting point or at least give an idea. (It actually solves the use cases that the people who wanted the feature are interested. That includes the cases in any issue report I had seen). Instead, I focused on describing the feature as completely as possible, which should help both the implementation and the consistency of the feature.
Sep 11 2019
parent reply jmh530 <john.michael.hall gmail.com> writes:
On Wednesday, 11 September 2019 at 22:30:31 UTC, Stefanos 
Baziotis wrote:
 [snip]
Another example of where something like what I had suggested above with constrained aliases might be useful. For whatever dumb reason, I was just playing around with restricting Algebraic to only allow numeric types. You have to create a new struct and add in some member functions to get it to work. You can do more-or-less the same thing with an alias, easier IMO, but then if a function calling that alias doesn't work as easily (for reasons discussed above in thread). import std.variant; import std.traits : isNumeric; import std.meta : allSatisfy; struct Foo(T...) if (allSatisfy!(isNumeric, T)) { Algebraic!(T) x; alias x this; this(U)(U val) { x = val; } void opAssign(U)(U val) { x = val; } } template Bar(T...) if (allSatisfy!(isNumeric, T)) { alias Bar = Algebraic!(T); } void useFoo(T...)(Foo!T x) { } void useBar(T...)(Bar!T x) { } void main() { import std.stdio : writeln; auto v = Foo!(int, double)(5); writeln(v.peek!(int)); writeln(v); v = 3.14; writeln(v.peek!(double)); writeln(v); auto w = Bar!(int, double)(5); useFoo(v); //useBar(w); //does not compile currently }
Sep 30 2019
parent Stefanos Baziotis <sdi1600105 di.uoa.gr> writes:
On Monday, 30 September 2019 at 19:16:47 UTC, jmh530 wrote:
 On Wednesday, 11 September 2019 at 22:30:31 UTC, Stefanos 
 Baziotis wrote:
 [snip]
Another example of where something like what I had suggested above with constrained aliases might be useful.
Thanks for the info. It happened that just yesterday I updated the DIP and when Mike finds a slot, we'll either move to round 2 or final. I believe that most of the problems discussed in this thread have been solved by abstracting the terminology. I think it's better to not discuss further here as a summary has already been written. But please feel free to drop a comment on the new thread, when it is posted. Best regards, Stefanos
Oct 01 2019
prev sibling parent reply jmh530 <john.michael.hall gmail.com> writes:
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) { }
Sep 11 2019
parent reply Stefanos Baziotis <sdi1600105 di.uoa.gr> writes:
On Wednesday, 11 September 2019 at 09:58:58 UTC, jmh530 wrote:
 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.
For me, this DIP is the most complicated DIP I have seen - _just_ to handle alias declarations / instatiations in function arguments. And it already takes a lot of things for granted (i.e. the `Gen` function in the DIP is not specified). I would not have been able to complete it without some help from one of my professors. What I mean is that this is not necessarily the easiest thing to understand and even if it was, I'm not an expert in writing formal specifications. Regarding the implementation, well.. this a particularly draft implementation. :P It is after 3 days of first opening DMD.
 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) {

 }
I understand the reasoning, yes. I also think it would be very beneficial. The problem is that throwing templates in general into the mix I think will make the DIP way complicated. Also, I don't think I will be able to derive a formal specification. Btw, IMHO, templates are in general under-specified. Both in D and C++. I might have missed something but to the best of my knowledge, they're constrained to intuitive descriptions and examples. Especially considering the C++'s `using`. And then it is left to the compiler implementor to get to a specific behavior. I tried this DIP to provide a formal specification for the subject. And I'm here to answer questions and receive corrections as I understand this is not necessarily the best formal specification ever. - Stefanos
Sep 11 2019
parent reply jmh530 <john.michael.hall gmail.com> writes:
On Wednesday, 11 September 2019 at 12:11:21 UTC, Stefanos 
Baziotis wrote:
 [snip]

 I understand the reasoning, yes. I also think it would be very 
 beneficial.
 The problem is that throwing templates in general into the mix 
 I think
 will make the DIP way complicated. Also, I don't think I will 
 be able
 to derive a formal specification.
Even if it's too complicated to support the use case I described above as part of this DIP, I still think this has a lot of value. Another reason I brought up that potential use case is that if it enabled that pattern then it might have helped convince Atila the DIP was a good idea if he could see the benefits with respect to one of his libraries.
 Btw, IMHO, templates are in general under-specified. Both in D 
 and C++.
 I might have missed something but to the best of my knowledge, 
 they're
 constrained to intuitive descriptions and examples. Especially 
 considering
 the C++'s `using`. And then it is left to the compiler 
 implementor
 to get to a specific behavior.
I'm sure people would appreciate any enhancements to the D specification.
Sep 11 2019
parent reply Stefanos Baziotis <sdi1600105 di.uoa.gr> writes:
On Wednesday, 11 September 2019 at 12:47:45 UTC, jmh530 wrote:
 Even if it's too complicated to support the use case I 
 described above as part of this DIP, I still think this has a 
 lot of value.
I agree!
 Another reason I brought up that potential use case is that if 
 it enabled that pattern then it might have helped convince 
 Atila the DIP was a good idea if he could see the benefits with 
 respect to one of his libraries.
While that's probably true, IMO both parties (i.e. the DIP author and the reviewer) should act objectively. Meaning, a use case of a reviewer should be no different than another use case.
 I'm sure people would appreciate any enhancements to the D 
 specification.
I agree! I would for sure. And I think compiler implementors as well. - Stefanos
Sep 11 2019
parent reply jmh530 <john.michael.hall gmail.com> writes:
On Wednesday, 11 September 2019 at 15:36:04 UTC, Stefanos 
Baziotis wrote:
 [snip]

 While that's probably true, IMO both parties
 (i.e. the DIP author and the reviewer) should act objectively.
 Meaning, a use case of a reviewer should be no different
 than another use case.
On this PR thread [1], Atila said he struggled to see the value in it. My objective was to think up an example where he would see the value. I don't dispute that Atila both should and would act objectively in reviewing the DIP. However, if someone says they don't see value in something, it can be helpful to provide additional examples that might show the value. [1] https://github.com/dlang/dmd/pull/9778
Sep 11 2019
parent Stefanos Baziotis <sdi1600105 di.uoa.gr> writes:
On Wednesday, 11 September 2019 at 15:52:18 UTC, jmh530 wrote:
 On this PR thread [1], Atila said he struggled to see the value 
 in it. My objective was to think up an example where he would 
 see the value. I don't dispute that Atila both should and would 
 act objectively in reviewing the DIP. However, if someone says 
 they don't see value in something, it can be helpful to provide 
 additional examples that might show the value.
Yes, thank you for that. I agree and I also assume that Atila will review this objectively. And if supporting this does not complicate the DIP significantly, it may as well be added. - Stefanos
Sep 11 2019
prev sibling parent reply Daniel Kozak <kozzi11 gmail.com> writes:
On Fri, Sep 6, 2019 at 2:34 PM Stefanos Baziotis via Digitalmars-d
<digitalmars-d puremagic.com> wrote:
 On Friday, 6 September 2019 at 12:17:11 UTC, rikki cattermole
 wrote:
 Your examples in abstract didn't look right.
 I ran the second to confirm my suspicion:

 onlineapp.d(9): Error: undefined identifier T
Could you paste the example that gave you this error? Btw, not all examples are compilable.
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) { }
Sep 06 2019
parent Stefanos Baziotis <sdi1600105 di.uoa.gr> writes:
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
Sep 06 2019
prev sibling parent jmh530 <john.michael.hall gmail.com> writes:
On Friday, 6 September 2019 at 11:45:48 UTC, Mike Parker wrote:
 [snip]
Very happy to see this.
Sep 06 2019