Thread overview | |||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|
|
June 17, 2009 [SO] Modifing local class instance in pure function | ||||
---|---|---|---|---|
| ||||
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? |
June 18, 2009 Re: [SO] Modifing local class instance in pure function | ||||
---|---|---|---|---|
| ||||
Posted in reply to Jesse Phillips Attachments: | 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 |
June 18, 2009 Re: [SO] Modifing local class instance in pure function | ||||
---|---|---|---|---|
| ||||
Posted in reply to div0 | 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_programming
>
Based on that, cons makes lisp not functional.
|
June 19, 2009 Re: [SO] Modifing local class instance in pure function | ||||
---|---|---|---|---|
| ||||
Posted in reply to div0 | 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_programming
>
I 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
|
June 19, 2009 Re: [SO] Modifing local class instance in pure function | ||||
---|---|---|---|---|
| ||||
Posted in reply to Steven Schveighoffer | 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
|
June 19, 2009 Re: [SO] Modifing local class instance in pure function | ||||
---|---|---|---|---|
| ||||
Posted in reply to Steven Schveighoffer Attachments: | Steven Schveighoffer wrote: > 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_programming >> > > I 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 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 |
June 19, 2009 Re: [SO] Modifing local class instance in pure function | ||||
---|---|---|---|---|
| ||||
Posted in reply to div0 | 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
|
June 19, 2009 Re: [SO] Modifing local class instance in pure function | ||||
---|---|---|---|---|
| ||||
Posted in reply to bearophile | 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 |
June 19, 2009 Re: [SO] Modifing local class instance in pure function | ||||
---|---|---|---|---|
| ||||
Posted in reply to div0 | 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 |
Copyright © 1999-2021 by the D Language Foundation