How to get an inout constructor working with a template wrapper

Steven Schveighoffer schveiguy at gmail.com
Fri Jul 27 14:34:54 UTC 2018


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


More information about the Digitalmars-d-learn mailing list