digitalmars.D.learn - [SO] Modifing local class instance in pure function
- Jesse Phillips (17/17) Jun 17 2009 http://stackoverflow.com/questions/1008803/how-to-use-pure-in-d-2-0
- div0 (16/36) Jun 18 2009 -----BEGIN PGP SIGNED MESSAGE-----
- BCS (2/7) Jun 18 2009 Based on that, cons makes lisp not functional.
- Steven Schveighoffer (49/52) Jun 18 2009 I once thought as you do. You are wrong. Memory allocation is a
- bearophile (45/45) Jun 19 2009 Steven Schveighoffer:
- Steven Schveighoffer (7/11) Jun 19 2009 Yes, I thought of that solution. I intentionally did not write the code...
- div0 (22/94) Jun 19 2009 -----BEGIN PGP SIGNED MESSAGE-----
- Steven Schveighoffer (3/5) Jun 19 2009 Arrays are not value types. Substitute int[] x with a pointer, same arg...
- bearophile (67/71) Jun 19 2009 Interesting question, I have tried the following code with D2:
http://stackoverflow.com/questions/1008803/how-to-use-pure-in-d-2-0 class TestPure { string[] msg; void addMsg( string s ) { msg ~= s; } }; pure TestPure run2() { TestPure t = new TestPure(); t.addMsg("Test"); t.addMsg("this."); return t; } This doesn't work and the answer from CyberShodow is that you could thread inside the pure function modifying the class value at the same time. Isn't that still an issue if TestPure was change to an int?
Jun 17 2009
-----BEGIN PGP SIGNED MESSAGE----- Hash: SHA1 Jesse Phillips wrote:http://stackoverflow.com/questions/1008803/how-to-use-pure-in-d-2-0 class TestPure { string[] msg; void addMsg( string s ) { msg ~= s; } }; pure TestPure run2() { TestPure t = new TestPure(); t.addMsg("Test"); t.addMsg("this."); return t; } This doesn't work and the answer from CyberShodow is that you could thread inside the pure function modifying the class value at the same time. Isn't that still an issue if TestPure was change to an int?Pure functions are not allowed to alter global state. That's what you doing when you create a new object. http://en.wikipedia.org/wiki/Functional_programming - -- My enormous talent is exceeded only by my outrageous laziness. http://www.ssTk.co.uk -----BEGIN PGP SIGNATURE----- Version: GnuPG v1.4.7 (MingW32) Comment: Using GnuPG with Mozilla - http://enigmail.mozdev.org iD8DBQFKOrzET9LetA9XoXwRAr7yAJ95tUQ5E6blpFHmnRCSaAcYdN1wCgCeLmZi Bg8FdF/yxx3iR4LS5T+NXsE= =0WQ0 -----END PGP SIGNATURE-----
Jun 18 2009
Reply to div0,Pure functions are not allowed to alter global state. That's what you doing when you create a new object. http://en.wikipedia.org/wiki/Functional_programmingBased on that, cons makes lisp not functional.
Jun 18 2009
On Thu, 18 Jun 2009 18:16:36 -0400, div0 <div0 users.sourceforge.net> wrote:Pure functions are not allowed to alter global state. That's what you doing when you create a new object. http://en.wikipedia.org/wiki/Functional_programmingI once thought as you do. You are wrong. Memory allocation is a necessary function, and although it is inherently unpure, it must be allowed in pure functions. The problem is that the function boundary is where purity is enforced, not inside. For instance, basic programming 101, split common tasks into functions: int[] f() { int[] x = new int[5]; foreach(i, ref n; x) n = i; return x; } int[] g() { int[] x = new int[6]; foreach(i, ref n; x) n = i; return x; } f and g can be pure, because they do not have side effects. However, consider: void fill(int[] x) { foreach(i, ref n; x) n = i; } int[] f() { int[] x = new int[5]; fill(x); return x; } Note that f is still pure, and fill is contextually pure, since in f's context, it is not altering external state. However, we cannot mark fill as pure, because when called from a non-pure function, it could alter external state. Therefore, fill cannot be called from f if f is pure. This is similar to calling a method on an object: C c = new C; c.method(); The method call translates to: C.method(c); The compiler cannot tell whether c is external state or not, just like it cannot tell that fill() can be contextually pure. So it is not allowed. I'm not sure what the solution is. Something like 'unique' which would ensure that exclusive ownership of an object passes to the method would possibly allow passing mutable state into a pure function. I'm unsure if there are any plans for something like this. -Steve
Jun 18 2009
Steven Schveighoffer:int[] f() { int[] x = new int[5]; foreach(i, ref n; x) n = i; return x; } int[] g() { int[] x = new int[6]; foreach(i, ref n; x) n = i; return x; } f and g can be pure, because they do not have side effects. However, consider: void fill(int[] x) { foreach(i, ref n; x) n = i; } int[] f() { int[] x = new int[5]; fill(x); return x; } [...] I'm not sure what the solution is. Something like 'unique' which would ensure that exclusive ownership of an object passes to the method would possibly allow passing mutable state into a pure function. I'm unsure if there are any plans for something like this. < Probably there are ways to solve the situation, using unique or something else, but I think that way leads to C++-style madness (see the ridiculously complex lambdas of the last C++, they look like a joke to me. Those designers have missed the point that the essential purpose of a lambda as used in mostly imperative languages is to simplify code and the like, so having one hundred optional features is bad). Keeping pure functions simple is the key to allow their optimizations. To solve your problem you can change your function fill() to restore its purity (code untested): pure void range(int n) { int[] arr = new int[n]; foreach (i, ref el; arr) el = i; return arr; } pure int[] f() { return range(5); } pure int[] g() { return range(6); } Or you can just accept to not mark fill(), f() and g() as pure. Bye, bearophile
Jun 19 2009
bearophile Wrote:Probably there are ways to solve the situation, using unique or something else, but I think that way leads to C++-style madness (see the ridiculously complex lambdas of the last C++, they look like a joke to me. Those designers have missed the point that the essential purpose of a lambda as used in mostly imperative languages is to simplify code and the like, so having one hundred optional features is bad). Keeping pure functions simple is the key to allow their optimizations.Such complexity is necessary when you are trying to encapsulate functional benefits with imperative style. I happen to think we need unique for const/multithreading anyways, why not extend that to help pure functions be modularized?To solve your problem you can change your function fill() to restore its purity (code untested):Yes, I thought of that solution. I intentionally did not write the code that way to illustrate the point I was trying to make. I'm expecting the reader to envision larger examples where it's not as convenient to change the modularization point, especially with previously existing functions that are hard to rewrite. Consider that you can't sort an array you create in a pure function without rewriting sort as a pure function!Or you can just accept to not mark fill(), f() and g() as pure.fill cannot be pure, because it is only contextually pure (pure when called from a pure function). I'm not saying there is an easy solution, but the problems are not completely solved by the current methodology. If they can be solved, I think D will be in a class of it's own. -Steve
Jun 19 2009
-----BEGIN PGP SIGNED MESSAGE----- Hash: SHA1 Steven Schveighoffer wrote:On Thu, 18 Jun 2009 18:16:36 -0400, div0 <div0 users.sourceforge.net> wrote:Nuts I missed the main point of what I meant to say. Though I can see the argument against the heap being global state is necessary or you won't be able to do much with pure functions. In your example you are returning values types, not objects as in the original question. Objects are defined to have an identity, so by returning a new object from the function you are not getting the same result for the same inputs. Does D relax the definition of pure to say a function may return an equivalent object? - -- My enormous talent is exceeded only by my outrageous laziness. http://www.ssTk.co.uk -----BEGIN PGP SIGNATURE----- Version: GnuPG v1.4.7 (MingW32) Comment: Using GnuPG with Mozilla - http://enigmail.mozdev.org iD8DBQFKO7EwT9LetA9XoXwRAkyiAJ0fUG20aU1IJSEa62yOCOTubvsmRgCgooGF CXT3z2MqmhA+4wx8UW0Dyqc= =uhBi -----END PGP SIGNATURE-----Pure functions are not allowed to alter global state. That's what you doing when you create a new object. http://en.wikipedia.org/wiki/Functional_programmingI once thought as you do. You are wrong. Memory allocation is a necessary function, and although it is inherently unpure, it must be allowed in pure functions. The problem is that the function boundary is where purity is enforced, not inside. For instance, basic programming 101, split common tasks into functions: int[] f() { int[] x = new int[5]; foreach(i, ref n; x) n = i; return x; } int[] g() { int[] x = new int[6]; foreach(i, ref n; x) n = i; return x; } f and g can be pure, because they do not have side effects. However, consider: void fill(int[] x) { foreach(i, ref n; x) n = i; } int[] f() { int[] x = new int[5]; fill(x); return x; } Note that f is still pure, and fill is contextually pure, since in f's context, it is not altering external state. However, we cannot mark fill as pure, because when called from a non-pure function, it could alter external state. Therefore, fill cannot be called from f if f is pure. This is similar to calling a method on an object: C c = new C; c.method(); The method call translates to: C.method(c); The compiler cannot tell whether c is external state or not, just like it cannot tell that fill() can be contextually pure. So it is not allowed. I'm not sure what the solution is. Something like 'unique' which would ensure that exclusive ownership of an object passes to the method would possibly allow passing mutable state into a pure function. I'm unsure if there are any plans for something like this. -Steve
Jun 19 2009
div0 Wrote:In your example you are returning values types, not objects as in the original question.Arrays are not value types. Substitute int[] x with a pointer, same argument applies. -Steve
Jun 19 2009
div0:Objects are defined to have an identity, so by returning a new object from the function you are not getting the same result for the same inputs. Does D relax the definition of pure to say a function may return an equivalent object?Interesting question, I have tried the following code with D2: import std.stdio: writeln; class C {} pure C genc() { return new C; } void main() { writeln(genc() is genc()); } The generated asm shows that pure of genc is ignored: With "pure": main: L0: push EBX mov EAX,offset FLAT:_D5temp31C7__ClassZ push EAX call near ptr __d_newclass add ESP,4 mov ECX,offset FLAT:_D5temp31C7__ClassZ push EAX sub ESP,4 push ECX call near ptr __d_newclass add ESP,4 add ESP,4 mov EDX,EAX mov EBX,1 pop EAX cmp EAX,EDX je L32 xor EBX,EBX L32: mov EAX,offset FLAT:_D3std5stdio6stdoutS3std5stdio4File push EBX push 0Ah call near ptr _D3std5stdio4File14__T5writeTbTaZ5writeMFbaZv xor EAX,EAX pop EBX ret Without "pure": main: L0: push EBX mov EAX,offset FLAT:_D5temp31C7__ClassZ push EAX call near ptr __d_newclass add ESP,4 mov ECX,offset FLAT:_D5temp31C7__ClassZ push EAX sub ESP,4 push ECX call near ptr __d_newclass add ESP,4 add ESP,4 mov EDX,EAX mov EBX,1 pop EAX cmp EAX,EDX je L32 xor EBX,EBX L32: mov EAX,offset FLAT:_D3std5stdio6stdoutS3std5stdio4File push EBX push 0Ah call near ptr _D3std5stdio4File14__T5writeTbTaZ5writeMFbaZv xor EAX,EAX pop EBX ret I don't know what's happening under the hood into dmd here, Don may give a better answer. Bye, bearophile
Jun 19 2009