www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.bugs - [Issue 22027] New: inout shouldn't imply return


          Issue ID: 22027
           Summary: inout shouldn't imply return
           Product: D
           Version: D2
          Hardware: All
                OS: All
            Status: NEW
          Keywords: safe
          Severity: enhancement
          Priority: P1
         Component: dmd
          Assignee: nobody puremagic.com
          Reporter: dkorpel live.nl

Currently `inout` parameters imply the `return` attribute. It's a special case,
adding complexity to the language and the compiler, and it doesn't make sense.
The rationale of it is:

 The idea is that the inout doesn't make sense if one is not returning 
 something based on the parameter marked with inout.
https://github.com/dlang/dmd/pull/10390#issuecomment-528774351 However, as pointed out by Rainer Schuetze, it's possible to return something else that has the same qualifier as the parameter but different lifetime. ``` struct Large { void[4000] data; } struct SImpl { Large d; } struct S { SImpl* impl; // GC managed? ref inout(Large) getLarge() inout { return impl.d; } } ``` https://github.com/dlang/dmd/pull/10390#issuecomment-529177731 In fact, here are examples of valid uses of inout with every combination of ref/return/scope, showing that it doesn't ever imply the need for `return`: ``` struct Node { int x; Node* next; inout(int*) next_v0() return inout {return &this.x;} inout(int*) next_v1() return scope inout {return &this.next.x;} inout(int*) next_v2() scope inout {return &this.next.next.x;} inout(int*) next_v3() inout {return &this.next.x;} ref inout(int) next_r0() return inout {return this.next.x;} ref inout(int) next_r1() scope inout {return this.next.next.x;} ref inout(int) next_r2() return scope inout {return this.next.next.x;} ref inout(int) next_r3() inout {return this.next.x;} } inout(int*) next_v0(return inout Node this_) {return &this_.next.x;} inout(int*) next_v1(return scope inout Node this_) {return &this_.next.x;} inout(int*) next_v2( scope inout Node this_) {return &this_.next.next.x;} inout(int*) next_v3( inout Node this_) {return &this_.next.x;} ref inout(int) next_r0(return inout Node this_) {return this_.next.x;} ref inout(int) next_r1(return scope inout Node this_) {return this_.next.x;} ref inout(int) next_r2( scope inout Node this_) {return this_.next.next.x;} ref inout(int) next_r3( inout Node this_) {return this_.next.x;} ``` It's also worth noting that the current implementation has a bug that's trivially fixed by removing the special case: https://issues.dlang.org/show_bug.cgi?id=20149 ``` safe: struct ScopeBuffer { char[4] buf; inout(char)[] getSlice() inout {return buf[];} } char[] fun() { char[4] buf = "abcd"; ScopeBuffer sb = ScopeBuffer(buf); return sb.getSlice; // dangling slice to stack memory is returned here } void main() { auto s = fun(); } ``` --
Jun 15 2021