|
Archives
D Programming
digitalmars.D
digitalmars.D.bugs
digitalmars.D.dtl
digitalmars.D.ide
digitalmars.D.dwt
digitalmars.D.announce
digitalmars.D.learn
digitalmars.D.debugger
D.gnu
D
C/C++ Programming
c++
c++.announce
c++.atl
c++.beta
c++.chat
c++.command-line
c++.dos
c++.dos.16-bits
c++.dos.32-bits
c++.idde
c++.mfc
c++.rtl
c++.stl
c++.stl.hp
c++.stl.port
c++.stl.sgi
c++.stlsoft
c++.windows
c++.windows.16-bits
c++.windows.32-bits
c++.wxwindows
digitalmars.empire
digitalmars.DMDScript
electronics
|
digitalmars.D.learn - [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?
-----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-----
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.
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
Steven Schveighoffer:
{
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
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
-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1
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
-----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-----
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
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
|
|