Thread overview | ||||||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
July 22, 2018 How to get an inout constructor working with a template wrapper | ||||
---|---|---|---|---|
| ||||
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 |
July 22, 2018 Re: How to get an inout constructor working with a template wrapper | ||||
---|---|---|---|---|
| ||||
Posted in reply to aliak | 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, > - Ali 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) |
July 23, 2018 Re: How to get an inout constructor working with a template wrapper | ||||
---|---|---|---|---|
| ||||
Posted in reply to Ali Çehreli | 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 |
July 23, 2018 Re: How to get an inout constructor working with a template wrapper | ||||
---|---|---|---|---|
| ||||
Posted in reply to aliak | On Monday, 23 July 2018 at 12:02:58 UTC, aliak wrote: > https://run.dlang.io/is/gd5oxW Sorry wrong link! This one is correct -> https://run.dlang.io/is/azxmGN |
July 23, 2018 Re: How to get an inout constructor working with a template wrapper | ||||
---|---|---|---|---|
| ||||
Posted in reply to aliak | 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, > - Ali 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)); } |
July 27, 2018 Re: How to get an inout constructor working with a template wrapper | ||||
---|---|---|---|---|
| ||||
Posted in reply to Timoses | On Monday, 23 July 2018 at 14:46:32 UTC, Timoses wrote: > On Monday, 23 July 2018 at 12:02:58 UTC, aliak wrote: >> [...] > > 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)); > } 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 |
July 27, 2018 Re: How to get an inout constructor working with a template wrapper | ||||
---|---|---|---|---|
| ||||
Posted in reply to aliak | On 7/23/18 8:02 AM, aliak wrote: > 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 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. > 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 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) 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 |
July 27, 2018 Re: How to get an inout constructor working with a template wrapper | ||||
---|---|---|---|---|
| ||||
Posted in reply to aliak | 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
|
July 28, 2018 Re: How to get an inout constructor working with a template wrapper | ||||
---|---|---|---|---|
| ||||
Posted in reply to Steven Schveighoffer | On Friday, 27 July 2018 at 14:38:27 UTC, Steven Schveighoffer wrote: > 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 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? |
July 28, 2018 Re: How to get an inout constructor working with a template wrapper | ||||
---|---|---|---|---|
| ||||
Posted in reply to Steven Schveighoffer | 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))? > >> >> 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. 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... > > -Steve |
Copyright © 1999-2021 by the D Language Foundation