digitalmars.D.learn - How to get an inout constructor working with a template wrapper
- aliak (25/25) Jul 22 2018 Hi,
- =?UTF-8?Q?Ali_=c3=87ehreli?= (27/52) Jul 22 2018 Without much confidence on my side, first, I think you need to make the
- aliak (21/47) Jul 23 2018 Thank you Ali! That helped :) I've gotten most of it sorted out
- aliak (3/4) Jul 23 2018 Sorry wrong link!
- Timoses (34/54) Jul 23 2018 Both of these seem to work (as you pointed out)
- aliak (17/54) Jul 27 2018 Ok, thanks to Simen from another post [0], I just figured out
- Steven Schveighoffer (5/22) Jul 27 2018 And instantiate a new template for all mutabilities. Whereas inout would...
- aliak (23/46) Jul 28 2018 If you change the ctor to be inout then you get (from the link
- Steven Schveighoffer (64/113) Jul 29 2018 No, you need to apply it to wrap as well. I can't get run.dlang.io to
- aliak (9/14) Jul 29 2018 Ah bugger, right!
- Steven Schveighoffer (5/17) Jul 31 2018 It's not that there's no way, the issue is simply that you are
- aliak (19/39) Jul 31 2018 Ok bear with me, but I'm really confused why
- Steven Schveighoffer (23/68) Jul 31 2018 Because inout is trying to combine all mutability modifiers into one.
- aliak (9/32) Jul 31 2018 Ahhh. Ok I see... I think.
- Steven Schveighoffer (29/86) Jul 27 2018 This seems like a bug to me.
- aliak (9/38) Jul 28 2018 Ah ok, so the compiler remove inout behind me back here? (And
Hi, In the code below: struct W(T) { T val; this(T val) inout { this.val = val; } } class C {} void main() { W!C a = new C; immutable W!C b = new C; } W!C a = new C results in: "Error: cannot implicitly convert expression val of type C to inout(C)." If I remove the inout on the constructor then the error is on the other line and is: "Error: mutable method W!(C).W.this is not callable using a immutable object" If the class is changed to a struct through, then the constructor with inout works on both lines in main above. So I guess this has something to do with reference types (As the same behaviour is exhibited if T == int*) What's the recommended way to handle this? Cheers, - Ali
Jul 22 2018
On 07/22/2018 03:51 PM, aliak wrote:Hi, In the code below: struct W(T) { T val; this(T val) inout { this.val = val; } } class C {} void main() { W!C a = new C; immutable W!C b = new C; } W!C a = new C results in: "Error: cannot implicitly convert expression val of type C to inout(C)." If I remove the inout on the constructor then the error is on the other line and is: "Error: mutable method W!(C).W.this is not callable using a immutable object" If the class is changed to a struct through, then the constructor with inout works on both lines in main above. So I guess this has something to do with reference types (As the same behaviour is exhibited if T == int*) What's the recommended way to handle this? Cheers, - AliWithout much confidence on my side, first, I think you need to make the constructor parameter inout(T) as well. Otherwise, you may be making a const(W!T) initialized with a non-const T. After that, I like the "type constructor" syntax in main_alt() below (which works) but a better approach is to use a convenience function like wrap() below: struct W(T) { T val; this(inout(T) val) inout { this.val = val; } } class C {} void main_alt() { auto a = W!C(new C); auto b = immutable W!(immutable C)(new C); } auto wrap(T)(inout T t) { return inout(W!T)(t); } void main() { auto a = wrap(new C); auto b = wrap(new immutable(C)); } Ali "taklitlerinden sakınınız" :o)
Jul 22 2018
On Sunday, 22 July 2018 at 23:11:09 UTC, Ali Çehreli wrote:Without much confidence on my side, first, I think you need to make the constructor parameter inout(T) as well. Otherwise, you may be making a const(W!T) initialized with a non-const T. After that, I like the "type constructor" syntax in main_alt() below (which works) but a better approach is to use a convenience function like wrap() below: struct W(T) { T val; this(inout(T) val) inout { this.val = val; } } class C {} void main_alt() { auto a = W!C(new C); auto b = immutable W!(immutable C)(new C); } auto wrap(T)(inout T t) { return inout(W!T)(t); } void main() { auto a = wrap(new C); auto b = wrap(new immutable(C)); } Ali "taklitlerinden sakınınız" :o)Thank you Ali! That helped :) I've gotten most of it sorted out now, and the factory wrap is definitely the way to go, it also turned out that inout(T) and inout T (so inout without parens) was surprisingly different (maybe it's a bug? - to test you can remove the parens around U on line 3 in this sample: https://run.dlang.io/is/gd5oxW Also over there, line 24: auto si = wrap!(immutable int)(3); seems to be giving problems. Any ideas there? Error is: onlineapp.d(8): Error: inout on return means inout must be on a parameter as well for pure nothrow nogc safe inout(W!(immutable(int)))(immutable(int) t) onlineapp.d(23): Error: template instance `onlineapp.wrap!(immutable(int))` error instantiating To make it compile successfully you can either: 1) Chance immutable to const, then it works for some reason. 2) Change the line to: "auto si = wrap(cast(immutable int)3);" - i.e. do not explicitly provide type information. Cheers, - Ali
Jul 23 2018
On Monday, 23 July 2018 at 12:02:58 UTC, aliak wrote:https://run.dlang.io/is/gd5oxWSorry wrong link! This one is correct -> https://run.dlang.io/is/azxmGN
Jul 23 2018
On Monday, 23 July 2018 at 12:02:58 UTC, aliak wrote:Thank you Ali! That helped :) I've gotten most of it sorted out now, and the factory wrap is definitely the way to go, it also turned out that inout(T) and inout T (so inout without parens) was surprisingly different (maybe it's a bug? - to test you can remove the parens around U on line 3 in this sample: https://run.dlang.io/is/gd5oxW Also over there, line 24: auto si = wrap!(immutable int)(3);Both of these seem to work (as you pointed out) // immutable(W!int) auto si = wrap!(int)(cast(immutable)3); // or wrap(cast(immutable)3); // W!(immutable(int)) auto si2 = W!(immutable int)(3);seems to be giving problems. Any ideas there? Error is: onlineapp.d(8): Error: inout on return means inout must be on a parameter as well for pure nothrow nogc safe inout(W!(immutable(int)))(immutable(int) t) onlineapp.d(23): Error: template instance `onlineapp.wrap!(immutable(int))` error instantiating To make it compile successfully you can either: 1) Chance immutable to const, then it works for some reason. 2) Change the line to: "auto si = wrap(cast(immutable int)3);" - i.e. do not explicitly provide type information.I don't know why wrap!(immutable int)(3); is not working. The error message "Error: inout on return means inout must be on a parameter as well for pure nothrow nogc safe inout(W!(immutable(int)))(return immutable(int) t)" sounds very odd and not at all helpful, at least regarding that removing immutable from the template argument works.Cheers, - AliThe depths of D. Why does the following only work with "return ref"? struct W(T) { T val; this(U : T)(auto ref inout U val) inout { pragma(msg, typeof(val)); this.val = val; } } // Fails without "return ref" (escaping t warning...) auto wrap(T)(return ref inout T t) { return inout W!T(t); } class C {} void main() { immutable C ci = new immutable C; auto i = wrap(im); pragma(msg, typeof(i)); }
Jul 23 2018
On Monday, 23 July 2018 at 14:46:32 UTC, Timoses wrote:On Monday, 23 July 2018 at 12:02:58 UTC, aliak wrote:Ok, thanks to Simen from another post [0], I just figured out what the correct constructor and factory method for a template wrapper should be: https://run.dlang.io/is/S4vHzL struct W(T) { T val; this(U : T, this This)(auto ref U val) { this.val = val; } } auto wrap(T)(auto ref T t) { return W!T(t); } Seems to catch all cases! [0]: https://forum.dlang.org/thread/hxbeektmpnmfdbvjrtcf forum.dlang.org[...]Both of these seem to work (as you pointed out) // immutable(W!int) auto si = wrap!(int)(cast(immutable)3); // or wrap(cast(immutable)3); // W!(immutable(int)) auto si2 = W!(immutable int)(3);[...]I don't know why wrap!(immutable int)(3); is not working. The error message "Error: inout on return means inout must be on a parameter as well for pure nothrow nogc safe inout(W!(immutable(int)))(return immutable(int) t)" sounds very odd and not at all helpful, at least regarding that removing immutable from the template argument works.[...]The depths of D. Why does the following only work with "return ref"? struct W(T) { T val; this(U : T)(auto ref inout U val) inout { pragma(msg, typeof(val)); this.val = val; } } // Fails without "return ref" (escaping t warning...) auto wrap(T)(return ref inout T t) { return inout W!T(t); } class C {} void main() { immutable C ci = new immutable C; auto i = wrap(im); pragma(msg, typeof(i)); }
Jul 27 2018
On 7/27/18 9:29 AM, aliak wrote:Ok, thanks to Simen from another post [0], I just figured out what the correct constructor and factory method for a template wrapper should be: https://run.dlang.io/is/S4vHzL struct W(T) { T val; this(U : T, this This)(auto ref U val) { this.val = val; } } auto wrap(T)(auto ref T t) { return W!T(t); } Seems to catch all cases!And instantiate a new template for all mutabilities. Whereas inout would only instantiate one (and disallows modification of val if not const or immutable). -Steve
Jul 27 2018
On Friday, 27 July 2018 at 14:38:27 UTC, Steven Schveighoffer wrote:On 7/27/18 9:29 AM, aliak wrote:If you change the ctor to be inout then you get (from the link above): onlineapp.d(4): Error: cannot implicitly convert expression val of type onlineapp.C to inout(C) onlineapp.d(28): Error: template instance `onlineapp.W!(C).W.__ctor!(C)` error instantiating onlineapp.d(4): Error: cannot implicitly convert expression val of type S1 to inout(S1) onlineapp.d(44): Error: template instance `onlineapp.W!(S1).W.__ctor!(S1)` error instantiating onlineapp.d(4): Error: cannot implicitly convert expression val of type onlineapp.C to inout(C) onlineapp.d(9): Error: template instance `onlineapp.W!(C).W.__ctor!(C)` error instantiating onlineapp.d(52): instantiated from here: wrap!(C) onlineapp.d(4): Error: cannot implicitly convert expression val of type const(C) to inout(const(C)) onlineapp.d(9): Error: template instance `onlineapp.W!(const(C)).W.__ctor!(const(C))` error instantiating onlineapp.d(53): instantiated from here: wrap!(const(C)) Am I applying inout incorrectly?Ok, thanks to Simen from another post [0], I just figured out what the correct constructor and factory method for a template wrapper should be: https://run.dlang.io/is/S4vHzL struct W(T) { T val; this(U : T, this This)(auto ref U val) { this.val = val; } } auto wrap(T)(auto ref T t) { return W!T(t); } Seems to catch all cases!And instantiate a new template for all mutabilities. Whereas inout would only instantiate one (and disallows modification of val if not const or immutable). -Steve
Jul 28 2018
On 7/28/18 6:09 PM, aliak wrote:On Friday, 27 July 2018 at 14:38:27 UTC, Steven Schveighoffer wrote:No, you need to apply it to wrap as well. I can't get run.dlang.io to work for posting a link, so here is my modified version: struct W(T) { T val; this(U : T)(auto ref inout(U) val) inout { this.val = val; } } auto wrap(T)(auto ref inout(T) t) { return inout W!T(t); } class C {} struct S0 {} struct S1 { C c; } void f_dprimitive() { int a = 3; const int b = 3; immutable int c = 3; const int d = a; immutable int e = a; auto sc = wrap(const(int)(3)); // note the modifications here auto si = wrap(immutable(int)(3)); } void f_class() { W!C a = new C(); const W!C b = new C(); immutable W!C c = new immutable C(); const W!C d = a; //immutable W!C e = a; // cannot implicitly convert mutable to immutable } void f_struct() { W!S0 a = S0(); const W!S0 b = S0(); immutable W!S0 c = S0(); const W!S0 d = a; immutable W!S0 e = a; } void f_struct_with_indirection() { W!S1 a = S1(); const W!S1 b = S1(); immutable W!S1 c = immutable S1(); const W!S1 d = a; // immutable W!S1 e = a; // cannot implicitly convert mutable to immutable } void f_wrapper() { auto a = wrap(new C); auto b = wrap(new const C); auto c = wrap(new immutable C); const W!C d = a; // immutable W!C e = a; // cannot implicitly convert mutable to immutable } void f_wrapper2() { Object ma = new C(); Object ca = new const C(); Object ia = new immutable C(); auto a = wrap(cast(C)ma); auto b = wrap(cast(const C)ma); auto c = wrap(cast(immutable C)ma); } void main() { }On 7/27/18 9:29 AM, aliak wrote:If you change the ctor to be inout then you get (from the link above): onlineapp.d(4): Error: cannot implicitly convert expression val of type onlineapp.C to inout(C) onlineapp.d(28): Error: template instance `onlineapp.W!(C).W.__ctor!(C)` error instantiating onlineapp.d(4): Error: cannot implicitly convert expression val of type S1 to inout(S1) onlineapp.d(44): Error: template instance `onlineapp.W!(S1).W.__ctor!(S1)` error instantiating onlineapp.d(4): Error: cannot implicitly convert expression val of type onlineapp.C to inout(C) onlineapp.d(9): Error: template instance `onlineapp.W!(C).W.__ctor!(C)` error instantiating onlineapp.d(52): instantiated from here: wrap!(C) onlineapp.d(4): Error: cannot implicitly convert expression val of type const(C) to inout(const(C)) onlineapp.d(9): Error: template instance `onlineapp.W!(const(C)).W.__ctor!(const(C))` error instantiating onlineapp.d(53): instantiated from here: wrap!(const(C)) Am I applying inout incorrectly?Ok, thanks to Simen from another post [0], I just figured out what the correct constructor and factory method for a template wrapper should be: https://run.dlang.io/is/S4vHzL struct W(T) { T val; this(U : T, this This)(auto ref U val) { this.val = val; } } auto wrap(T)(auto ref T t) { return W!T(t); } Seems to catch all cases!And instantiate a new template for all mutabilities. Whereas inout would only instantiate one (and disallows modification of val if not const or immutable). -Steve
Jul 29 2018
On Sunday, 29 July 2018 at 12:45:48 UTC, Steven Schveighoffer wrote:Ah bugger, right! Ok so there's no way to make explicit instantiation involving immutable work in the face of an inout parameter? Seems rather inconsistent no? https://issues.dlang.org/show_bug.cgi?id=19126 Thanks, - AliAm I applying inout incorrectly?No, you need to apply it to wrap as well. I can't get run.dlang.io to work for posting a link, so here is my modified version:
Jul 29 2018
On 7/29/18 1:46 PM, aliak wrote:On Sunday, 29 July 2018 at 12:45:48 UTC, Steven Schveighoffer wrote:It's not that there's no way, the issue is simply that you are explicitly instantiating incorrectly. wrap!int(immutable(int)(3)); -SteveAh bugger, right! Ok so there's no way to make explicit instantiation involving immutable work in the face of an inout parameter? Seems rather inconsistent no?Am I applying inout incorrectly?No, you need to apply it to wrap as well. I can't get run.dlang.io to work for posting a link, so here is my modified version:
Jul 31 2018
On Tuesday, 31 July 2018 at 12:37:34 UTC, Steven Schveighoffer wrote:On 7/29/18 1:46 PM, aliak wrote:Ok bear with me, but I'm really confused why "wrap!int(immutable(int)(3))" is "correct". This all seems very inconsistent: 1. wrap!(int)(3); // ok 2. wrap!(const int)(3); // ok 3. wrap!(immutable int)(3); // nope 4. wrap!(int)(3); // ok 5. wrap!(const int)(const(int)(3)); // ok 6. wrap!(immutable int)(immutable(int)(3)); // ok! So for 3, compiler sees the instantiation: inout(W!(immutable int)) wrap(immutable(int)) If I understood you correctly? But then what does it see in number 6, which works fine? And why is 2 ok if 3 is not? And finally, why can't the compiler leave the inout there and then it doesn't need to complain about it? Cheers, - AliOn Sunday, 29 July 2018 at 12:45:48 UTC, Steven Schveighoffer wrote:It's not that there's no way, the issue is simply that you are explicitly instantiating incorrectly. wrap!int(immutable(int)(3)); -SteveAh bugger, right! Ok so there's no way to make explicit instantiation involving immutable work in the face of an inout parameter? Seems rather inconsistent no?Am I applying inout incorrectly?No, you need to apply it to wrap as well. I can't get run.dlang.io to work for posting a link, so here is my modified version:
Jul 31 2018
On 7/31/18 5:29 PM, aliak wrote:On Tuesday, 31 July 2018 at 12:37:34 UTC, Steven Schveighoffer wrote:Because inout is trying to combine all mutability modifiers into one. You want to specify the type, not the mutability, in the template parameter T. Essentially, if this were a normal function that takes only ints, you would write it once for all mutabilities: auto wrap(inout(int) x) Which works for mutable, const, or immutable int.On 7/29/18 1:46 PM, aliak wrote:Ok bear with me, but I'm really confused why "wrap!int(immutable(int)(3))" is "correct".On Sunday, 29 July 2018 at 12:45:48 UTC, Steven Schveighoffer wrote:It's not that there's no way, the issue is simply that you are explicitly instantiating incorrectly. wrap!int(immutable(int)(3));Ah bugger, right! Ok so there's no way to make explicit instantiation involving immutable work in the face of an inout parameter? Seems rather inconsistent no?Am I applying inout incorrectly?No, you need to apply it to wrap as well. I can't get run.dlang.io to work for posting a link, so here is my modified version:This all seems very inconsistent: 1. wrap!(int)(3); // ok 2. wrap!(const int)(3); // ok 3. wrap!(immutable int)(3); // nope 4. wrap!(int)(3); // ok 5. wrap!(const int)(const(int)(3)); // ok 6. wrap!(immutable int)(immutable(int)(3)); // ok!This doesn't make sense. Can you post runnable code? When I go back to your original failing example, and replace the 3 with immutable(int)(3), it still fails.So for 3, compiler sees the instantiation: inout(W!(immutable int)) wrap(immutable(int)) If I understood you correctly?Yes. You can see for yourself with pragma msg: pragma(msg, typeof(t)); // immutable(int)But then what does it see in number 6, which works fine?I'm skeptical this is the case. Note that you may only see the instantiation error ONCE.And why is 2 ok if 3 is not?because inout(const(T)) cannot have its inout removed.And finally, why can't the compiler leave the inout there and then it doesn't need to complain about it?It has to strip inout to be consistent -- we want canonical types. It's the same reason immutable(const(int)) is just immutable(int), and const(const(const(int))) is just const(int). Having the original types be left in place would make for some weird rules. But the complaint is really the issue. Clearly inout is specified, so it shouldn't complain that it isn't. -Steve
Jul 31 2018
On Tuesday, 31 July 2018 at 21:54:54 UTC, Steven Schveighoffer wrote:Because inout is trying to combine all mutability modifiers into one. You want to specify the type, not the mutability, in the template parameter T.Ahhh. Ok I see... I think.This doesn't make sense. Can you post runnable code?Hehe, ok, so I fell victim to compiler generating an error for number 3 and then nothing else :p But yes you're right, if I comment out number 3 then 6 errors as well. Sorry my bad!When I go back to your original failing example, and replace the 3 with immutable(int)(3), it still fails.Yep, you nailed that one.So for 3, compiler sees the instantiation: inout(W!(immutable int)) wrap(immutable(int)) If I understood you correctly?Yes. You can see for yourself with pragma msg: pragma(msg, typeof(t)); // immutable(int)But then what does it see in number 6, which works fine?I'm skeptical this is the case. Note that you may only see the instantiation error ONCE.Because it may be an immutable? Or?And why is 2 ok if 3 is not?because inout(const(T)) cannot have its inout removed.But the complaint is really the issue. Clearly inout is specified, so it shouldn't complain that it isn't.Aye. I guess that's right.-Steve
Jul 31 2018
On 7/23/18 8:02 AM, aliak wrote:On Sunday, 22 July 2018 at 23:11:09 UTC, Ali Çehreli wrote:This seems like a bug to me. The semantic difference is that inout(U) means the TYPE inout(U), whereas inout U means the variable U has the STORAGE CLASS inout, which also happens to make it an inout(U) type. As far as I know, the storage class inout shouldn't have any other effect on the semantic meaning. I can't imagine any difference there, but it appears to not recognize that return should be inferred? I don't know.Without much confidence on my side, first, I think you need to make the constructor parameter inout(T) as well. Otherwise, you may be making a const(W!T) initialized with a non-const T. After that, I like the "type constructor" syntax in main_alt() below (which works) but a better approach is to use a convenience function like wrap() below: struct W(T) { T val; this(inout(T) val) inout { this.val = val; } } class C {} void main_alt() { auto a = W!C(new C); auto b = immutable W!(immutable C)(new C); } auto wrap(T)(inout T t) { return inout(W!T)(t); } void main() { auto a = wrap(new C); auto b = wrap(new immutable(C)); } Ali "taklitlerinden sakınınız" :o)Thank you Ali! That helped :) I've gotten most of it sorted out now, and the factory wrap is definitely the way to go, it also turned out that inout(T) and inout T (so inout without parens) was surprisingly different (maybe it's a bug? - to test you can remove the parens around U on line 3 in this sample: https://run.dlang.io/is/gd5oxWAlso over there, line 24: auto si = wrap!(immutable int)(3); seems to be giving problems. Any ideas there? Error is: onlineapp.d(8): Error: inout on return means inout must be on a parameter as well for pure nothrow nogc safe inout(W!(immutable(int)))(immutable(int) t) onlineapp.d(23): Error: template instance `onlineapp.wrap!(immutable(int))` error instantiatingThe problem here is that inout(immutable(int)) is equivalent to immutable(int). That is, all flavors of mutability are equivalent to immutable(int): /*mutable*/(immutable(int)) => immutable(int) const(immutable(int)) => immutable(int) immutable(immutable(int)) => immutable(int) So the compiler really looks at your wrap instantiation like this; inout(W!(immutable(int))) wrap(immutable(int) t) which triggers the (really bad) message. I'd ask, why are you even worrying about explicit instantiation? Why not just wrap(3)? or (if you really want to test it) wrap(immutable(int)(3))?To make it compile successfully you can either: 1) Chance immutable to const, then it works for some reason.Because immutable(const(int)) => immutable(int), so the compiler can't remove the inout behind your back.2) Change the line to: "auto si = wrap(cast(immutable int)3);" - i.e. do not explicitly provide type information.Yep, do this :) Note that the point of inout is 2-fold: 1. reduce template instantiations. In fact, wrap!int works for const, mutable and immutable int. 2. ENSURE that the data isn't modified, even in the case of mutable parameters. -Steve
Jul 27 2018
On Friday, 27 July 2018 at 14:34:54 UTC, Steven Schveighoffer wrote:The problem here is that inout(immutable(int)) is equivalent to immutable(int). That is, all flavors of mutability are equivalent to immutable(int): /*mutable*/(immutable(int)) => immutable(int) const(immutable(int)) => immutable(int) immutable(immutable(int)) => immutable(int) So the compiler really looks at your wrap instantiation like this; inout(W!(immutable(int))) wrap(immutable(int) t)Ah ok, so the compiler remove inout behind me back here? (And then tells me it needs to be there? :p)which triggers the (really bad) message. I'd ask, why are you even worrying about explicit instantiation? Why not just wrap(3)?Just because I don't see why it should not work really. Why not allow wrap!(immutable int)(3)?or (if you really want to test it) wrap(immutable(int)(3))?Thanks for the explanations! For some reason it's hard to get it all to *just work* right now without the template this. But it's probably some minor detail I'm just overlooking...To make it compile successfully you can either: 1) Chance immutable to const, then it works for some reason.Because immutable(const(int)) => immutable(int), so the compiler can't remove the inout behind your back.2) Change the line to: "auto si = wrap(cast(immutable int)3);" - i.e. do not explicitly provide type information.Yep, do this :) Note that the point of inout is 2-fold: 1. reduce template instantiations. In fact, wrap!int works for const, mutable and immutable int. 2. ENSURE that the data isn't modified, even in the case of mutable parameters.-Steve
Jul 28 2018