digitalmars.dip.development - First Draft: Implicit Conversion of Template Instantiations
- Walter Bright (2/2) Mar 16 https://github.com/WalterBright/documents/blob/9dba63a4c2887bdb2b988c354...
- Dukc (18/24) Mar 16 Nope. It will instantiate it as `void bar(int*) const`.
- andy (2/6) Mar 16
- Walter Bright (2/5) Mar 17 The same typo that was in my slides and fixed :-/
- max haughton (5/7) Mar 17 I once wrote a small patch to the compiler that added a syntax to
- Timon Gehr (26/29) Mar 17 In general: Yes, I think something along those lines would be great.
- Walter Bright (6/14) Mar 18 I'm not convinced it is clean, nor am I convinced that it is dangerous. ...
- Timon Gehr (19/22) Mar 17 Keep in mind that to get rid of qualifier magic, you also have to add
- Walter Bright (2/3) Mar 18 These already are supposed to work.
- Walter Bright (3/3) Mar 18 Oops.
- Timon Gehr (16/19) Mar 17 Issue: It does not seem to work yet for class references:
- Walter Bright (4/5) Mar 18 It only works for const conversion. Not for inheritance conversions. We ...
- Timon Gehr (63/66) Mar 17 Idea: Explicit variance annotations.
- Timon Gehr (3/14) Mar 17 A way to address this would be to also allow `struct S(+-T)`, which
- Timon Gehr (21/24) Mar 17 Issue: I think the field names also have to match.
- Walter Bright (2/3) Mar 18 I think you're right.
- Timon Gehr (21/24) Mar 17 Issue: Subtyping under indirections remains magic.
- Timon Gehr (12/20) Mar 17 Another example of a similar kind of issue:
- Walter Bright (2/15) Mar 18 That should work.
https://github.com/WalterBright/documents/blob/9dba63a4c2887bdb2b988c354ebb0d6bb44c4968/templatecast.md DConf: https://dconf.org/2024/online/index.html#walterb
Mar 16
On Saturday, 16 March 2024 at 15:50:27 UTC, Walter Bright wrote:https://github.com/WalterBright/documents/blob/9dba63a4c2887bdb2b988c354ebb0d6bb44c4968/templatecast.mdThanks. Having a look:But `const X!(int*)` will instantiate `bar` as `void bar(int*)`.Nope. It will instantiate it as `void bar(int*) const`.The template struct or template class will be treated as a list of its members.Three points. 1. Why wouldn't this apply only to templated structs? It'd make sense for the rules to apply to all structs/classes. 2. In the presented example, no fields are actually converted. The only field, `x`, is the same type in both cases (`const(int[])`). Please add an example where type of the field(s) differ, say converting `X!(immutable(int))` to `const(X!int)`. 3. Could allowing these casts break assumptions of a type that has ` system` fields (DIP1035)? I haven't thought it deeply enough to conclude one way pr another but the DIP should probably explain it.Only members that are fields or non-static functions are considered.I don't see why member functions would need to be considered, static or no. An instance of a struct doesn't contain it's member functions as fields.
Mar 16
On Saturday, 16 March 2024 at 15:50:27 UTC, Walter Bright wrote:https://github.com/WalterBright/documents/blob/9dba63a4c2887bdb2b988c354ebb0d6bb44c4968/templatecast.md DConf: https://dconf.org/2024/online/index.html#walterbThere must be a typo here:Consider also that const(int)[] and const(int)[] are not the same type, either
Mar 16
On 3/16/2024 5:06 PM, andy wrote:There must be a typo here:The same typo that was in my slides and fixed :-/Consider also that const(int)[] and const(int)[] are not the same type, either
Mar 17
On Saturday, 16 March 2024 at 15:50:27 UTC, Walter Bright wrote:https://github.com/WalterBright/documents/blob/9dba63a4c2887bdb2b988c354ebb0d6bb44c4968/templatecast.md DConf: https://dconf.org/2024/online/index.html#walterbI once wrote a small patch to the compiler that added a syntax to enable user defined conversions for this exact use case, can't remember the syntax I came up with (it was a bit like an is expression suffixing the template parameters), must dig it up.
Mar 17
On 3/16/24 16:50, Walter Bright wrote:https://github.com/WalterBright/documents/blob/9dba63a4c2887bdb2b988c354ebb0d6bb44c4968/templatecast.md DConf: https://dconf.org/2024/online/index.html#walterbIn general: Yes, I think something along those lines would be great. From my DConf question: ```d struct S(alias a){ void f(){ a(); } } void main(){ import std.stdio; S!({ writeln("first"); }) s1; S!({ writeln("second"); }) s2 = s1; // ok s1.f(); // first s2.f(); // second pragma(msg, is(typeof(s1):typeof(s2))); // true } ``` I think this is a bit dangerous. (And on stream you seemed to argue that this has the potential to kill the proposal.) I think the way to fix it would be to simply use a more strict standard than "must belong to the same template". Add an opt-in annotation to template parameters that indicates "this parameter may change in a const conversion". For other parameters, you still require them to match by default. This way, people can opt into the behavior.
Mar 17
On 3/17/2024 5:32 PM, Timon Gehr wrote:I think this is a bit dangerous. (And on stream you seemed to argue that this has the potential to kill the proposal.)I'm not convinced it is clean, nor am I convinced that it is dangerous. One solution would be simply to reject alias arguments that are functions. In general, the way may be to just keep rejecting things at compile time that aren't correct.I think the way to fix it would be to simply use a more strict standard than "must belong to the same template". Add an opt-in annotation to template parameters that indicates "this parameter may change in a const conversion". For other parameters, you still require them to match by default. This way, people can opt into the behavior.I hear you, but I am concerned about yet another annotation.
Mar 18
On 3/16/24 16:50, Walter Bright wrote:https://github.com/WalterBright/documents/blob/9dba63a4c2887bdb2b988c354ebb0d6bb44c4968/templatecast.md DConf: https://dconf.org/2024/online/index.html#walterbKeep in mind that to get rid of qualifier magic, you also have to add common types: ```d struct S(T){ T[] payload; } void main(){ immutable a1 = [1,2,3]; auto a2 = [1,2,3]; assert(a1 == a2); auto s1 = S!(immutable(int))(a1); auto s2 = S!(int)(a2); assert(s1 == s2); // TODO auto a3 = [a1, a2]; auto s3 = [s1, s2]; // TODO } ``` This is a bit more tricky.
Mar 17
On 3/17/2024 5:38 PM, Timon Gehr wrote:This is a bit more tricky.These already are supposed to work.
Mar 18
Oops. This will not work, only the top level qualifiers are convertible, not the next level down.
Mar 18
On 3/16/24 16:50, Walter Bright wrote:https://github.com/WalterBright/documents/blob/9dba63a4c2887bdb2b988c354ebb0d6bb44c4968/templatecast.md DConf: https://dconf.org/2024/online/index.html#walterbIssue: It does not seem to work yet for class references: ```d struct S(T){ T a; } class A{} class B:A{} void main(){ S!(const(int)[]) s1 = S!(int[])([1,2,3]); // ok S!A s2=S!B(new A); // error } ``` The B is an A in essentially the same way an `int[]` is a `const(int)[]`. (Subtyping, no change in memory representation required for conversion.)
Mar 17
On 3/17/2024 5:45 PM, Timon Gehr wrote:Issue: It does not seem to work yet for class references:It only works for const conversion. Not for inheritance conversions. We could perhaps add the latter later, but I want to stick with const conversion only for now.
Mar 18
On 3/16/24 16:50, Walter Bright wrote:https://github.com/WalterBright/documents/blob/9dba63a4c2887bdb2b988c354ebb0d6bb44c4968/templatecast.md DConf: https://dconf.org/2024/online/index.html#walterbIdea: Explicit variance annotations. Benefits: - Makes it easy to determine a common type. - I expect overall faster compilation, because subtyping can be refuted without analyzing all fields. - Solves question of how to annotate in an opt-in solution. (I think opt-in is absolutely required for this feature.) - Very easy to implement by simple additions on top of the existing prototype. - Principled. Drawbacks: - Slightly more expensive to determine that subtyping holds. (First, you check the arguments according to the variance annotations, if that succeeds, you still have to perform the member-wise check.) - This particular proposal would disallow a template type with variance of one template parameter varying based on one of the other template parameters. E.g. ```d struct S(+T){ T payload; } ``` This annotation means that `S` is _covariant_ in `T`. Intuitively, this means that an rvalue of type `S!T` can produce values of type `T`. Other examples: ```d struct S(+T){ T foo(); } ``` ```d struct S(+T){ void foo(void delegate(T) callback){} } ``` The common type of `S!T1` and `S!T2` is `S!T3`, where `T3` is the common type of `T1` and `T2`. ``d struct S(-T){ void delegate(T) payload; } ``` This annotation means that `S` is _contravariant_ in `T`. Intuitively, this means that an rvalue of type `S!T` can consume values of type `T`. The common type of `S!T1` and `S!T2` is `S!T3`, where `T3` is the shared type of `T1` and `T2`. The implementation currently also supports a case like this one: ```d struct S(T){ T[] payload; } ``` Here, `S` is covariant in `T` only if converting to a non-mutable type. This would require a different annotation, I suggest `+const`. ```d struct S(+const T){ T[] payload; } ``` In principle we could also have `-const`, but currently I do not see a case where that would be helpful.
Mar 17
On 3/18/24 02:11, Timon Gehr wrote:Drawbacks: - Slightly more expensive to determine that subtyping holds. (First, you check the arguments according to the variance annotations, if that succeeds, you still have to perform the member-wise check.) - This particular proposal would disallow a template type with variance of one template parameter varying based on one of the other template parameters.A way to address this would be to also allow `struct S(+-T)`, which always just uses the field-wise check.
Mar 17
On 3/16/24 16:50, Walter Bright wrote:https://github.com/WalterBright/documents/blob/9dba63a4c2887bdb2b988c354ebb0d6bb44c4968/templatecast.md DConf: https://dconf.org/2024/online/index.html#walterbIssue: I think the field names also have to match. Consider: ```d struct S(bool swapped,T1,T2){ static if(swapped){ T2 second; T1 first; }else{ T1 first; T2 second; } } void main(){ import std.stdio; auto s1=S!(true,int,int)(1,2); S!(false,int,int) s2=s1; writeln(s1.first," ",s1.second); // 1 2 writeln(s2.first," ",s2.second); // 2 1 } ```
Mar 17
On 3/17/2024 6:17 PM, Timon Gehr wrote:Issue: I think the field names also have to match.I think you're right.
Mar 18
On 3/16/24 16:50, Walter Bright wrote:https://github.com/WalterBright/documents/blob/9dba63a4c2887bdb2b988c354ebb0d6bb44c4968/templatecast.md DConf: https://dconf.org/2024/online/index.html#walterbIssue: Subtyping under indirections remains magic. ```d struct Mutability(bool mutable,T){ static if(mutable){ T payload; }else{ const(T) payload; } } void main(){ int[] a1 = [1,2,3]; const(int)[] a2 = a1; // ok auto m1=[Mutability!(true,int)(1), Mutability!(true,int)(2), Mutability!(true,int)(3)]; Mutability!(false,int)[] m2=m1; // error } ``` (With variance annotations, this example would need some kind of support for variance annotations for template value parameters.)
Mar 17
On 3/18/24 02:28, Timon Gehr wrote:On 3/16/24 16:50, Walter Bright wrote:Another example of a similar kind of issue: ```d struct S(T){ T x; } void main(){ S!int[] a = [S!int(1),S!int(2),S!int(3)]; S!(const(int))[] b = a; // error } ``` I think this one may be just an oversight in the prototype implementation.https://github.com/WalterBright/documents/blob/9dba63a4c2887bdb2b988c354ebb0d6bb44c4968/templatecast.md DConf: https://dconf.org/2024/online/index.html#walterbIssue: Subtyping under indirections remains magic. ...
Mar 17
On 3/17/2024 6:32 PM, Timon Gehr wrote:Another example of a similar kind of issue: ```d struct S(T){ T x; } void main(){ S!int[] a = [S!int(1),S!int(2),S!int(3)]; S!(const(int))[] b = a; // error } ``` I think this one may be just an oversight in the prototype implementation.That should work.
Mar 18