digitalmars.D - DIP 1023--Resolution of Template Alias Formal Parameters in Template
- Mike Parker (15/15) Sep 06 2019 This is the feedback thread for the first round of Community
- rikki cattermole (20/20) Sep 06 2019 The D code blocks should have the language set to D (```d ... ```) for
- Stefanos Baziotis (8/30) Sep 06 2019 Thanks, I didn't know about that.
- Mike Parker (7/9) Sep 06 2019 My bad. I should have caught that when I was revising.
- rikki cattermole (17/59) Sep 06 2019 This one should be since it is stating current behavior.
- Stefanos Baziotis (8/24) Sep 06 2019 Thanks Mike and jmh530.
- rikki cattermole (5/37) Sep 06 2019 No.
- Stefanos Baziotis (3/9) Sep 06 2019 Ah yes of course, thanks for referencing it.
- jmh530 (49/51) Sep 10 2019 I'm sure I could find some way to simplify this what's below, but
- Stefanos Baziotis (12/64) Sep 10 2019 TBH, I did not understand completely the code. From what I can
- jmh530 (17/24) Sep 10 2019 What do you mean there is no alias? This is an alias:
- jmh530 (16/17) Sep 10 2019 Here is a simpler example:
- Stefanos Baziotis (7/24) Sep 10 2019 Thanks, that is clearer. And I understand the reasoning now.
- Stefanos Baziotis (41/43) Sep 10 2019 Actually, just checked on the draft PR, it doesn't work.
- ag0aep6g (14/16) Sep 10 2019 A "template alias" is nothing but a (simple) template that resolves to
- Stefanos Baziotis (35/42) Sep 11 2019 We should be more precise here. 2 things that are semantically
- ag0aep6g (19/57) Sep 11 2019 Ok, sure. The difference is in syntax. It's the compiler's job to
- Stefanos Baziotis (28/46) Sep 11 2019 It doesn't change the meaning of alias. It changes how
- ag0aep6g (15/41) Sep 11 2019 So you intend to introduce a difference between shorthand and longhand
- Stefanos Baziotis (29/42) Sep 11 2019 Not necessarily. But let's say I do (as it seems the DIP
- ag0aep6g (36/47) Sep 11 2019 The longhand is a common way. If you base your DIP on the longhand only,...
- Stefanos Baziotis (28/52) Sep 11 2019 I agree, changes have to be done though. Meaning, it should
- jmh530 (46/47) Sep 30 2019 Another example of where something like what I had suggested
- Stefanos Baziotis (13/18) Oct 01 2019 Thanks for the info. It happened that just yesterday I updated
- jmh530 (31/36) Sep 11 2019 No problem. ag0aep6g's comments above are also pretty spot on.
- Stefanos Baziotis (33/62) Sep 11 2019 For me, this DIP is the most complicated DIP I have seen - _just_
- jmh530 (10/27) Sep 11 2019 Even if it's too complicated to support the use case I described
- Stefanos Baziotis (9/18) Sep 11 2019 While that's probably true, IMO both parties
- jmh530 (9/14) Sep 11 2019 On this PR thread [1], Atila said he struggled to see the value
- Stefanos Baziotis (6/12) Sep 11 2019 Yes, thank you for that. I agree and I also assume that Atila
- Daniel Kozak (5/15) Sep 06 2019 The issue is that your abstract is wrong. You have missed T
- Stefanos Baziotis (3/6) Sep 06 2019 Yes, is was pointed out and acknowledged above.
- jmh530 (2/3) Sep 06 2019 Very happy to see this.
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
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
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 TCould 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
On Friday, 6 September 2019 at 12:27:50 UTC, Stefanos Baziotis wrote: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.mdThanks, I didn't know about that.
Sep 06 2019
On 07/09/2019 12:27 AM, Stefanos Baziotis wrote:On Friday, 6 September 2019 at 12:17:11 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) { } ```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 TCould you paste the example that gave you this error? Btw, not all examples are compilable.I replied with this so that you had feedback for improving the DIP if other people find it hard to understand.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
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
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:Unless Mike says otherwise, yes.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?No. It is for future reference if there is a trend of people finding it hard to follow.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
On Friday, 6 September 2019 at 13:10:49 UTC, rikki cattermole wrote:Ah yes of course, thanks for referencing it.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
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
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: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.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; }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
On Tuesday, 10 September 2019 at 21:48:33 UTC, Stefanos Baziotis wrote:[snip]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.htmlTBH, 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.
Sep 10 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? }
Sep 10 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: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[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
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
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
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
On 11.09.19 13:49, Stefanos Baziotis wrote:On Wednesday, 11 September 2019 at 05:32:22 UTC, ag0aep6g wrote:Ok, sure. The difference is in syntax. It's the compiler's job to interpret the shorthand variant exactly like the longhand.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.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
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
On 11.09.19 17:48, Stefanos Baziotis wrote:On Wednesday, 11 September 2019 at 14:14:31 UTC, ag0aep6g wrote:[...]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. [...]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.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
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
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
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.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.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
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
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: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[snip]Another example of where something like what I had suggested above with constrained aliases might be useful.
Oct 01 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. - StefanosNo 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
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
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
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
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
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
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: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) { }Your examples in abstract didn't look right. I ran the second to confirm my suspicion: onlineapp.d(9): Error: undefined identifier TCould you paste the example that gave you this error? Btw, not all examples are compilable.
Sep 06 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
Sep 06 2019
On Friday, 6 September 2019 at 11:45:48 UTC, Mike Parker wrote:[snip]Very happy to see this.
Sep 06 2019