digitalmars.D - Immutable nested functions
- Tomek =?ISO-8859-2?Q?Sowi=F1ski?= (41/41) Jan 04 2011 A while ago I pointed out that the result of an immutably pure function ...
- Tomek =?ISO-8859-2?Q?Sowi=F1ski?= (6/7) Jan 06 2011 Two days, no answer. I was told that silence means agreement on this NG ...
- Daniel Murphy (28/39) Jan 06 2011 Defining a member function to be immutable doesn't mean it can only acce...
- Tomek =?ISO-8859-2?Q?Sowi=F1ski?= (17/47) Jan 07 2011 =20
- Don (9/59) Jan 07 2011 There is.
- Robert Jacques (4/71) Jan 07 2011 Umm... int delegate(int) pure square = delegate(int z) pure { return
- Tomek =?ISO-8859-2?Q?Sowi=F1ski?= (13/31) Jan 08 2011 , =20
A while ago I pointed out that the result of an immutably pure function (all arguments immutable, doesn't mutate globals) can be safely converted to immutable. More here: http://d.puremagic.com/issues/show_bug.cgi?id=5081 It helps with building complex immutable structures. Problem is, virtually every construction site is different so one is forced to define a new initializer function every time. To illustrate: void main() { immutable Node* init_leaf = ... ; uint breadth = ... ; immutable Node* tree = grow_tree(init_leaf, breadth); } Node* grow_tree(immutable Node* init_leaf, uint breadth) pure { Node* root = new Node; foreach (0..breadth) { Node* leaf = new Node(init_leaf); leaf.parent = root; root.leaves ~= leaf; } return root; } I tried to find a way to create ad-hoc functions conveniently. Naturally, I turned to nested functions: void main() { immutable Node* init_leaf = ... ; uint breadth = ... ; Node* grow_tree() pure immutable { Node* root = new Node; foreach (0..breadth) { Node* leaf = new Node(init_leaf); leaf.parent = root; root.leaves ~= leaf; } return root; } immutable Node* tree = grow_tree(); } Nested functions to be immutably pure must also guarantee that nothing gets mutated through its stack frame pointer. But there's a problem -- the compiler won't accept 'immutable' on a nested function. I think it should -- just like an immutable member function (e.g. in a class) is allowed to play only with immutable members of that class, an immutable nested function should be allowed to play only with the immutable members of the stack frame. It may seem a lesser change but I'm pretty excited as it solves the long-standing problems with immutable structure initialization. Excitement aside, I got questions: 1. I'm proposing to proliferate the concept of immutability from 'this' reference to a stack frame pointer. Although I'm confident it makes sense as these are interchangeable in delegates, I could use some criticism to either reject or strengthen the idea. 2. What about delegates? Should there be means to express a "delegate that doesn't mutate through its 'this'/stack frame pointer"? What should the syntax be for defining such delegate type and for lambdas (delegate literals)? 3. (vaguely related) Should there be means to express annotated delegates in general (e.g. pure, nothrow). What about annotated lambdas? -- Tomek
Jan 04 2011
Tomek Sowi=F1ski napisa=B3:[snip]Two days, no answer. I was told that silence means agreement on this NG but= this is extreme ;-) Seriously, what did I do wrong? Too long/boring post? --=20 Tomek
Jan 06 2011
"Tomek Sowinski" <just ask.me> wrote in message news:20110104222343.00004d47 unknown...Nested functions to be immutably pure must also guarantee that nothing gets mutated through its stack frame pointer. But there's a problem -- the compiler won't accept 'immutable' on a nested function. I think it should -- just like an immutable member function (e.g. in a class) is allowed to play only with immutable members of that class, an immutable nested function should be allowed to play only with the immutable members of the stack frame. It may seem a lesser change but I'm pretty excited as it solves the long-standing problems with immutable structure initialization.just like an immutable member function (e.g. in a class) is allowed to play only with immutable members of that classDefining a member function to be immutable doesn't mean it can only access immutable member variables, it means it must be called with an immutable class reference. class C { void fun() immutable {} } void main() { auto c = new C(); c.fun(); // error auto i = new immutable C(); i.fun(); // ok } For nested functions, the reference is to the enclosing function's stack frame. What does it mean to have this be immutable? Maybe this makes sense if EVERY variable in the enclosing stack frame is immutable? Is there any reason you couldn't just use static nested pure functions? void main() { static pure Node* grow_tree(int breadth) // strongly pure { .... } immutable Node* tree = grow_tree(...); }
Jan 06 2011
Daniel Murphy napisa=B3:Defining a member function to be immutable doesn't mean it can only acces=s=20immutable member variables, it means it must be called with an immutable==20class reference. =20 class C { void fun() immutable {} } =20 void main() { auto c =3D new C(); c.fun(); // error auto i =3D new immutable C(); i.fun(); // ok } =20 For nested functions, the reference is to the enclosing function's stack==20frame. What does it mean to have this be immutable? Maybe this makes se=nse=20if EVERY variable in the enclosing stack frame is immutable?Good point. I think the concept of immutable nested functions is still a so= lid improvement, even with requiring every variable of the enclosing stack = frame to be immutable.Is there any reason you couldn't just use static nested pure functions? =20 void main() { static pure Node* grow_tree(int breadth) // strongly pure { .... } immutable Node* tree =3D grow_tree(...); }I fear one would need to tediously add arguments for *every* ingredient in = the scope to be able to cook them inside. And if an ingredient turns out no= t necessary as the software evolves, there's the tedium of removing it from= the nested function signature, which -- let's face it -- nobody does. Init= ializing immutable structures is fairly common and lack of a convenient way= to do it has been recognized as one of the shortcomings of the const syste= m. It can and should be solved. --=20 Tomek
Jan 07 2011
Tomek Sowin'ski wrote:A while ago I pointed out that the result of an immutably pure function (all arguments immutable, doesn't mutate globals) can be safely converted to immutable. More here: http://d.puremagic.com/issues/show_bug.cgi?id=5081 It helps with building complex immutable structures. Problem is, virtually every construction site is different so one is forced to define a new initializer function every time. To illustrate: void main() { immutable Node* init_leaf = ... ; uint breadth = ... ; immutable Node* tree = grow_tree(init_leaf, breadth); } Node* grow_tree(immutable Node* init_leaf, uint breadth) pure { Node* root = new Node; foreach (0..breadth) { Node* leaf = new Node(init_leaf); leaf.parent = root; root.leaves ~= leaf; } return root; } I tried to find a way to create ad-hoc functions conveniently. Naturally, I turned to nested functions: void main() { immutable Node* init_leaf = ... ; uint breadth = ... ; Node* grow_tree() pure immutable { Node* root = new Node; foreach (0..breadth) { Node* leaf = new Node(init_leaf); leaf.parent = root; root.leaves ~= leaf; } return root; } immutable Node* tree = grow_tree(); } Nested functions to be immutably pure must also guarantee that nothing gets mutated through its stack frame pointer. But there's a problem -- the compiler won't accept 'immutable' on a nested function. I think it should -- just like an immutable member function (e.g. in a class) is allowed to play only with immutable members of that class, an immutable nested function should be allowed to play only with the immutable members of the stack frame. It may seem a lesser change but I'm pretty excited as it solves the long-standing problems with immutable structure initialization. Excitement aside, I got questions: 1. I'm proposing to proliferate the concept of immutability from 'this' reference to a stack frame pointer. Although I'm confident it makes sense as these are interchangeable in delegates, I could use some criticism to either reject or strengthen the idea. 2. What about delegates? Should there be means to express a "delegate that doesn't mutate through its 'this'/stack frame pointer"? What should the syntax be for defining such delegate type and for lambdas (delegate literals)? 3. (vaguely related) Should there be means to express annotated delegates in general (e.g. pure, nothrow).There is. int delegate(int) pure square = cast( int delegate(int z) pure ) (int z) { return z*z; };What about annotated lambdas?See the line above -- at the moment it requires a cast. Yuck yuck yuck. The other option would be for the compiler to automatically determine purity. I believe it always has access to the source code of the lambda, so there should be no problem to determine purity.
Jan 07 2011
On Fri, 07 Jan 2011 17:18:39 -0500, Don <nospam nospam.com> wrote:Tomek Sowin'ski wrote:Umm... int delegate(int) pure square = delegate(int z) pure { return z*z; }; compiles and runs fine. What doesn't compile is (int z) pure { return z*z; }; or anything similar.A while ago I pointed out that the result of an immutably pure function (all arguments immutable, doesn't mutate globals) can be safely converted to immutable. More here: http://d.puremagic.com/issues/show_bug.cgi?id=5081 It helps with building complex immutable structures. Problem is, virtually every construction site is different so one is forced to define a new initializer function every time. To illustrate: void main() { immutable Node* init_leaf = ... ; uint breadth = ... ; immutable Node* tree = grow_tree(init_leaf, breadth); } Node* grow_tree(immutable Node* init_leaf, uint breadth) pure { Node* root = new Node; foreach (0..breadth) { Node* leaf = new Node(init_leaf); leaf.parent = root; root.leaves ~= leaf; } return root; } I tried to find a way to create ad-hoc functions conveniently. Naturally, I turned to nested functions: void main() { immutable Node* init_leaf = ... ; uint breadth = ... ; Node* grow_tree() pure immutable { Node* root = new Node; foreach (0..breadth) { Node* leaf = new Node(init_leaf); leaf.parent = root; root.leaves ~= leaf; } return root; } immutable Node* tree = grow_tree(); } Nested functions to be immutably pure must also guarantee that nothing gets mutated through its stack frame pointer. But there's a problem -- the compiler won't accept 'immutable' on a nested function. I think it should -- just like an immutable member function (e.g. in a class) is allowed to play only with immutable members of that class, an immutable nested function should be allowed to play only with the immutable members of the stack frame. It may seem a lesser change but I'm pretty excited as it solves the long-standing problems with immutable structure initialization. Excitement aside, I got questions: 1. I'm proposing to proliferate the concept of immutability from 'this' reference to a stack frame pointer. Although I'm confident it makes sense as these are interchangeable in delegates, I could use some criticism to either reject or strengthen the idea. 2. What about delegates? Should there be means to express a "delegate that doesn't mutate through its 'this'/stack frame pointer"? What should the syntax be for defining such delegate type and for lambdas (delegate literals)? 3. (vaguely related) Should there be means to express annotated delegates in general (e.g. pure, nothrow).There is. int delegate(int) pure square = cast( int delegate(int z) pure ) (int z) { return z*z; };What about annotated lambdas?See the line above -- at the moment it requires a cast. Yuck yuck yuck. The other option would be for the compiler to automatically determine purity. I believe it always has access to the source code of the lambda, so there should be no problem to determine purity.
Jan 07 2011
Robert Jacques napisa=B3:=203. (vaguely related) Should there be means to express annotated =20 delegates in general (e.g. pure, nothrow). =20There is. int delegate(int) pure square =3D cast( int delegate(int z) pure ) (int z) { return z*z; }; =20What about annotated lambdas? =20See the line above -- at the moment it requires a cast. Yuck yuck yuck. The other option would be for the compiler to automatically determine =, =20purity. I believe it always has access to the source code of the lambda==20so there should be no problem to determine purity. =20=20 Umm... int delegate(int) pure square =3D delegate(int z) pure { return =z*z; }; compiles and runs fine. What doesn't compile is (int z) pure { =20 return z*z; }; or anything similar.Hm, you're right. Also, the argument list seems to be required with annotat= ions: int delegate() pure dg =3D delegate pure { return 0; }; // error int delegate() pure dg =3D delegate() pure { return 0; }; // compiles BTW, the syntax landscape seems densely populated, I wonder if demanded con= structs like pure { } wouldn't confuse the parser in some corner-case. It's all just syntax, though. I'm glad there's any way to get the job done. --=20 Tomek
Jan 08 2011