www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - Using inout in delegate

reply Jacob Carlborg <doob me.com> writes:
The following code fails to compile:

void foo (inout int[] arr)
{
     auto dg = {
         foreach (i, e ; arr) {}
     };
     dg();
}

void main ()
{
     auto a = [3, 4, 5];
     foo(a);
}

Error message:

main.d(9): Error: variable main.foo.__lambda1.__aggr1174 inout variables 
can only be declared inside inout functions
main.d(9): Error: variable main.foo.__lambda1.e inout variables can only 
be declared inside inout functions

If I remove the delegate everything compiles. Am I doing something wrong?

-- 
/Jacob Carlborg
Mar 28 2013
next sibling parent Timon Gehr <timon.gehr gmx.ch> writes:
On 03/28/2013 09:34 AM, Jacob Carlborg wrote:
 The following code fails to compile:

 void foo (inout int[] arr)
 {
      auto dg = {
          foreach (i, e ; arr) {}
      };
      dg();
 }

 void main ()
 {
      auto a = [3, 4, 5];
      foo(a);
 }

 Error message:

 main.d(9): Error: variable main.foo.__lambda1.__aggr1174 inout variables
 can only be declared inside inout functions
 main.d(9): Error: variable main.foo.__lambda1.e inout variables can only
 be declared inside inout functions

 If I remove the delegate everything compiles. Am I doing something wrong?
It is a bug / problem with inout's design.
Mar 28 2013
prev sibling parent reply "Steven Schveighoffer" <schveiguy yahoo.com> writes:
On Thu, 28 Mar 2013 04:34:36 -0400, Jacob Carlborg <doob me.com> wrote:

 The following code fails to compile:

 void foo (inout int[] arr)
 {
      auto dg = {
          foreach (i, e ; arr) {}
      };
      dg();
 }

 void main ()
 {
      auto a = [3, 4, 5];
      foo(a);
 }

 Error message:

 main.d(9): Error: variable main.foo.__lambda1.__aggr1174 inout variables  
 can only be declared inside inout functions
 main.d(9): Error: variable main.foo.__lambda1.e inout variables can only  
 be declared inside inout functions

 If I remove the delegate everything compiles. Am I doing something wrong?
Like Timon said, it's a bug in inout design. I'm not sure what __aggr1174 is, but you can fix the e error by specifying the type for e (or specifying it as const). I'm assuming the issue is that the compiler is trying to generate a struct to hold the stack data for foo, and struct members cannot be inout. It is a difficult problem to solve, because inout has two meanings depending on whether it is a parameter/return or a local variable. At some point, we need to address this, because inout has so much potential, but suffers from some large deficiencies. -Steve
Mar 28 2013
next sibling parent "Kagamin" <spam here.lot> writes:
well, closure is effectively a struct, so its fields should be 
properly qualified, e.g. as const.
Mar 28 2013
prev sibling next sibling parent Jacob Carlborg <doob me.com> writes:
On 2013-03-28 15:16, Steven Schveighoffer wrote:

 Like Timon said, it's a bug in inout design.

 I'm not sure what __aggr1174 is, but you can fix the e error by
 specifying the type for e (or specifying it as const).

 I'm assuming the issue is that the compiler is trying to generate a
 struct to hold the stack data for foo, and struct members cannot be inout.

 It is a difficult problem to solve, because inout has two meanings
 depending on whether it is a parameter/return or a local variable.  At
 some point, we need to address this, because inout has so much
 potential, but suffers from some large deficiencies.
I had to change to a regular for-loop and declare the element as "const": for (size_t i = 0; i < arr.length; i++) { const e = arr[e]; } -- /Jacob Carlborg
Mar 28 2013
prev sibling next sibling parent reply "Maxim Fomin" <maxim maxim-fomin.ru> writes:
On Thursday, 28 March 2013 at 14:16:27 UTC, Steven Schveighoffer 
wrote:
 I'm not sure what __aggr1174 is, but you can fix the e error by 
 specifying the type for e (or specifying it as const).

 -Steve
This is a foolishness of dmd frontend. It generates names for copies, temporaries, etc. These names are not only visible (a user can receive error messages referring to such names with no idea what are the variables the compiler is talking about) but accessible which allows to do funny nonsense stuff, probably bypassing type system. http://dpaste.dzfl.pl/15d67a77 Dmd is the only compiler I am aware of which makes visible internal stuff and allows to manipulate it. These names are created almost anywhere where there is parameter passing, temporary, foreach loop, a tuple access, a lambda or a delegate literal and in many other cases. Judging by console dump of this stuff when compiling phobos, I come to conclusion that dmd for ages is able to accept enormous amount of invalid code.
Mar 28 2013
parent reply "Kagamin" <spam here.lot> writes:
On Thursday, 28 March 2013 at 16:34:47 UTC, Maxim Fomin wrote:
 probably bypassing type system.
try to bypass the type system; we just saw the variables are typechecked.
Mar 29 2013
parent reply "Maxim Fomin" <maxim maxim-fomin.ru> writes:
On Friday, 29 March 2013 at 09:03:11 UTC, Kagamin wrote:
 On Thursday, 28 March 2013 at 16:34:47 UTC, Maxim Fomin wrote:
 probably bypassing type system.
try to bypass the type system; we just saw the variables are typechecked.
You saw one particular example, the problem is much bigger.
Mar 29 2013
parent reply "Kagamin" <spam here.lot> writes:
On Friday, 29 March 2013 at 10:37:42 UTC, Maxim Fomin wrote:
 You saw one particular example, the problem is much bigger.
What's problem? Try it.
Apr 01 2013
parent "Maxim Fomin" <maxim maxim-fomin.ru> writes:
On Monday, 1 April 2013 at 20:37:34 UTC, Kagamin wrote:
 On Friday, 29 March 2013 at 10:37:42 UTC, Maxim Fomin wrote:
 You saw one particular example, the problem is much bigger.
What's problem? Try it.
??? What to try? It seems there is misunderstanding. I point out that dmd generates names for pretty much internal staff and does not protect them, so they can be manipulated which is accepts-invalid. Such manipulation can probably lead to bypassing type system constraints. The fact that one particular example does not allow to do so, does not necessarily means that no one can. "Program testing can be used to show the presence of bugs, but never to show their absence!" Dijkstra.
Apr 01 2013
prev sibling parent reply "Kenji Hara" <k.hara.pg gmail.com> writes:
On Thursday, 28 March 2013 at 14:16:27 UTC, Steven Schveighoffer 
wrote:
 On Thu, 28 Mar 2013 04:34:36 -0400, Jacob Carlborg 
 <doob me.com> wrote:

 The following code fails to compile:

 void foo (inout int[] arr)
 {
     auto dg = {
         foreach (i, e ; arr) {}
     };
     dg();
 }

 void main ()
 {
     auto a = [3, 4, 5];
     foo(a);
 }

 Error message:

 main.d(9): Error: variable main.foo.__lambda1.__aggr1174 inout 
 variables can only be declared inside inout functions
 main.d(9): Error: variable main.foo.__lambda1.e inout 
 variables can only be declared inside inout functions

 If I remove the delegate everything compiles. Am I doing 
 something wrong?
Like Timon said, it's a bug in inout design.
I think this is not a hole of inout design. In this case, the lambda inside foo should capture 'inout' context pointer. void foo (inout int[] arr) { auto dg = { foreach (i, e ; arr) {} }; pragma(msg, typeof(dg)); // should print "void delegate() inout" dg(); }
 I'm assuming the issue is that the compiler is trying to 
 generate a struct to hold the stack data for foo, and struct 
 members cannot be inout.
It is true, but in this case, the context which is implicitly captured by closure is not directly accessible from programmers. So qualifying it 'inout' is safe.
 It is a difficult problem to solve, because inout has two 
 meanings depending on whether it is a parameter/return or a 
 local variable.  At some point, we need to address this, 
 because inout has so much potential, but suffers from some 
 large deficiencies.
And, inout closure cannot escape from enclosing inout function. auto foo(inout int[] arr) { auto dg = (inout int[] a) { return arr; // returns captured inout 'arr' }; return dg; // escape! (should be rejected statically) } If compiler does not reject escape... void main() { const int[] a = [3, 4, 5]; auto dg = foo(a); // typeof(dg) == inout(int[]) delegate(inout(int[])) int[] b = dg([]); assert(b.ptr == a.ptr); // type-system breaking! } Kenji Hara
Apr 02 2013
parent reply Jacob Carlborg <doob me.com> writes:
On 2013-04-02 15:03, Kenji Hara wrote:

 I think this is not a hole of inout design. In this case, the lambda
 inside foo should capture 'inout' context pointer.

 void foo (inout int[] arr)
 {
      auto dg = {
          foreach (i, e ; arr) {}
      };
      pragma(msg, typeof(dg));  // should print "void delegate() inout"
      dg();
 }

 I'm assuming the issue is that the compiler is trying to generate a
 struct to hold the stack data for foo, and struct members cannot be
 inout.
It is true, but in this case, the context which is implicitly captured by closure is not directly accessible from programmers. So qualifying it 'inout' is safe.
 It is a difficult problem to solve, because inout has two meanings
 depending on whether it is a parameter/return or a local variable.  At
 some point, we need to address this, because inout has so much
 potential, but suffers from some large deficiencies.
And, inout closure cannot escape from enclosing inout function. auto foo(inout int[] arr) { auto dg = (inout int[] a) { return arr; // returns captured inout 'arr' }; return dg; // escape! (should be rejected statically) } If compiler does not reject escape... void main() { const int[] a = [3, 4, 5]; auto dg = foo(a); // typeof(dg) == inout(int[]) delegate(inout(int[])) int[] b = dg([]); assert(b.ptr == a.ptr); // type-system breaking! } Kenji Hara
Then I should probably report this as an issue. -- /Jacob Carlborg
Apr 02 2013
parent Jacob Carlborg <doob me.com> writes:
On 2013-04-02 16:17, Jacob Carlborg wrote:

 Then I should probably report this as an issue.
http://d.puremagic.com/issues/show_bug.cgi?id=9859 -- /Jacob Carlborg
Apr 02 2013