digitalmars.D.learn - Pure delegate not quite pure?
- Tofu Ninja (22/22) Jun 28 2015 module main;
- "Marc =?UTF-8?B?U2Now7x0eiI=?= <schuetzm gmx.net> (5/27) Jun 28 2015 Just guessing: The context is treated as an implicit parameter of
- anonymous (28/50) Jun 28 2015 Here's a similar example where it's a bit clearer what's going on:
- Tofu Ninja (2/3) Jun 30 2015 Is there any way to annotate the context as const?
- Steven Schveighoffer (5/8) Jun 30 2015 const x = 4 ;)
- Tofu Ninja (6/15) Jun 30 2015 Yeah, but I am more worried about d changing x by itself(though
- Steven Schveighoffer (6/22) Jun 30 2015 Have you tried placing const on the function signature? i.e.:
- Tofu Ninja (3/8) Jun 30 2015 Nah, says its only available for non-static member functions.
- Tofu Ninja (7/18) Jun 30 2015 Also wouldn't being able to annotate it immutable(also doesn't
- Jesse Phillips (4/15) Jun 30 2015 hmm, it seems that this would be an appropriate enhancement. It
- Tofu Ninja (4/20) Jun 30 2015 const, immutable, shared, inout. Not sure if they all make sense
- Steven Schveighoffer (29/48) Jul 01 2015 immutable is probably incorrect without a cast, since immutable cannot
- Tofu Ninja (16/46) Jul 01 2015 The benefit of tagging it immutable would be to require the
module main; import std.stdio; void main(string[] args) { auto d = foo(); writeln(d()); // prints 25 } auto foo() { int x = 4; pure int delegate() d = delegate() { return x*x; }; writeln(d()); // prints 16 x = 5; writeln(d()); // prints 25 return d; } I can see that after foo returns, then d will truly be pure as x will no longer be modifiable, but just before that, it seems d is not actually pure. Is this the intended behavior?
Jun 28 2015
On Sunday, 28 June 2015 at 09:19:16 UTC, Tofu Ninja wrote:module main; import std.stdio; void main(string[] args) { auto d = foo(); writeln(d()); // prints 25 } auto foo() { int x = 4; pure int delegate() d = delegate() { return x*x; }; writeln(d()); // prints 16 x = 5; writeln(d()); // prints 25 return d; } I can see that after foo returns, then d will truly be pure as x will no longer be modifiable, but just before that, it seems d is not actually pure. Is this the intended behavior?Just guessing: The context is treated as an implicit parameter of `d` (analogous to `this` for a struct/class). Access to `x` counts a access through a parameter and therefore doesn't violate purity.
Jun 28 2015
On Sunday, 28 June 2015 at 09:19:16 UTC, Tofu Ninja wrote:module main; import std.stdio; void main(string[] args) { auto d = foo(); writeln(d()); // prints 25 } auto foo() { int x = 4; pure int delegate() d = delegate() { return x*x; }; writeln(d()); // prints 16 x = 5; writeln(d()); // prints 25 return d; } I can see that after foo returns, then d will truly be pure as x will no longer be modifiable, but just before that, it seems d is not actually pure. Is this the intended behavior?Here's a similar example where it's a bit clearer what's going on: ---- struct S { int x = 0; int d() pure {return ++this.x;} } void main() { S s; int delegate() pure d = &s.d; import std.stdio; writeln(d()); /* prints "1" */ writeln(d()); /* prints "2" */ writeln(d()); /* prints "3" */ } ---- `d` isn't all that pure, right? You're seeing the concept of "weak purity" in action. In D, the attribute `pure` really just means "doesn't access global mutable state". The function is still allowed to mutate any arguments it gets, including hidden ones. Here the method `d` has a hidden `this` parameter, and it can mutate data through it. With a nested function, the enclosing context is passed via a hidden parameter. Properly/mathematically/strongly pure functions have additional requirements on top of being marked `pure`. Read more here: http://klickverbot.at/blog/2012/05/purity-in-d/
Jun 28 2015
On Sunday, 28 June 2015 at 10:19:05 UTC, anonymous wrote:[...]Is there any way to annotate the context as const?
Jun 30 2015
On 6/30/15 5:23 PM, Tofu Ninja wrote:On Sunday, 28 June 2015 at 10:19:05 UTC, anonymous wrote:const x = 4 ;) But even if you could annotate just the *reference* as const, it doesn't stop foo from changing it as you did in the example. -Steve[...]Is there any way to annotate the context as const?
Jun 30 2015
On Tuesday, 30 June 2015 at 21:31:05 UTC, Steven Schveighoffer wrote:On 6/30/15 5:23 PM, Tofu Ninja wrote:Yeah, but I am more worried about d changing x by itself(though foo changing it is still a problem), I have a piece of code that takes a delegate and I want to ensure that it runs in the same way every time once it's given to me.On Sunday, 28 June 2015 at 10:19:05 UTC, anonymous wrote:const x = 4 ;) But even if you could annotate just the *reference* as const, it doesn't stop foo from changing it as you did in the example. -Steve[...]Is there any way to annotate the context as const?
Jun 30 2015
On 6/30/15 5:44 PM, Tofu Ninja wrote:On Tuesday, 30 June 2015 at 21:31:05 UTC, Steven Schveighoffer wrote:Have you tried placing const on the function signature? i.e.: pure int delegate() const d = () const {... That's how you'd do it (I think, didn't test) if the delegate context pointer was a class/struct. -SteveOn 6/30/15 5:23 PM, Tofu Ninja wrote:Yeah, but I am more worried about d changing x by itself(though foo changing it is still a problem), I have a piece of code that takes a delegate and I want to ensure that it runs in the same way every time once it's given to me.On Sunday, 28 June 2015 at 10:19:05 UTC, anonymous wrote:const x = 4 ;) But even if you could annotate just the *reference* as const, it doesn't stop foo from changing it as you did in the example.[...]Is there any way to annotate the context as const?
Jun 30 2015
On Tuesday, 30 June 2015 at 22:05:43 UTC, Steven Schveighoffer wrote:Have you tried placing const on the function signature? i.e.: pure int delegate() const d = () const {... That's how you'd do it (I think, didn't test) if the delegate context pointer was a class/struct. -SteveNah, says its only available for non-static member functions.
Jun 30 2015
On Tuesday, 30 June 2015 at 22:23:40 UTC, Tofu Ninja wrote:On Tuesday, 30 June 2015 at 22:05:43 UTC, Steven Schveighoffer wrote:Also wouldn't being able to annotate it immutable(also doesn't work) solve both problems. If the context was immutable then everything in it would have to be as well, d couldn't change it and foo wouldn't be able to as well because every thing in the context would have to be immutable. Or maybe I am understanding it wrong.Have you tried placing const on the function signature? i.e.: pure int delegate() const d = () const {... That's how you'd do it (I think, didn't test) if the delegate context pointer was a class/struct. -SteveNah, says its only available for non-static member functions.
Jun 30 2015
On Tuesday, 30 June 2015 at 22:23:40 UTC, Tofu Ninja wrote:On Tuesday, 30 June 2015 at 22:05:43 UTC, Steven Schveighoffer wrote:hmm, it seems that this would be an appropriate enhancement. It doesn't make sense on a function, but as it relates to delegates I'd say it makes sense to allow const to be added.Have you tried placing const on the function signature? i.e.: pure int delegate() const d = () const {... That's how you'd do it (I think, didn't test) if the delegate context pointer was a class/struct. -SteveNah, says its only available for non-static member functions.
Jun 30 2015
On Wednesday, 1 July 2015 at 00:13:36 UTC, Jesse Phillips wrote:On Tuesday, 30 June 2015 at 22:23:40 UTC, Tofu Ninja wrote:const, immutable, shared, inout. Not sure if they all make sense on delegates, but those are the options for member functions, so they might apply to delegates as well.On Tuesday, 30 June 2015 at 22:05:43 UTC, Steven Schveighoffer wrote:hmm, it seems that this would be an appropriate enhancement. It doesn't make sense on a function, but as it relates to delegates I'd say it makes sense to allow const to be added.Have you tried placing const on the function signature? i.e.: pure int delegate() const d = () const {... That's how you'd do it (I think, didn't test) if the delegate context pointer was a class/struct. -SteveNah, says its only available for non-static member functions.
Jun 30 2015
On 6/30/15 9:29 PM, Tofu Ninja wrote:On Wednesday, 1 July 2015 at 00:13:36 UTC, Jesse Phillips wrote:immutable is probably incorrect without a cast, since immutable cannot be applied implicitly to non-immutable data, and if the data is all immutable already, no sense in tagging it immutable. I really see use in allowing const. inout is sketchy, I'm trying to think of how this applies, since inout is really for data types that are varied in their constancy. A function has only one addressable instance. shared, well... I don't think we need it. Function stacks shouldn't be shared. One thing you CAN do as a workaround, is put all your data to return into a static struct, and return delegates that address your data: auto foo() { static struct Storage { int x = 4; pure int dg() immutable { return x * x;} // should be strong-pure } immutable(Storage) s; auto d = &s.dg; // I *think* this allocates a closure, but if not, that's a bug. writeln(d()); // s.x = 5; // invalid return d; } Really, a delegate on a function stack is like a single-instance private-defined struct like written above. -SteveOn Tuesday, 30 June 2015 at 22:23:40 UTC, Tofu Ninja wrote:const, immutable, shared, inout. Not sure if they all make sense on delegates, but those are the options for member functions, so they might apply to delegates as well.On Tuesday, 30 June 2015 at 22:05:43 UTC, Steven Schveighoffer wrote:hmm, it seems that this would be an appropriate enhancement. It doesn't make sense on a function, but as it relates to delegates I'd say it makes sense to allow const to be added.Have you tried placing const on the function signature? i.e.: pure int delegate() const d = () const {... That's how you'd do it (I think, didn't test) if the delegate context pointer was a class/struct.Nah, says its only available for non-static member functions.
Jul 01 2015
On Wednesday, 1 July 2015 at 12:34:35 UTC, Steven Schveighoffer wrote:immutable is probably incorrect without a cast, since immutable cannot be applied implicitly to non-immutable data, and if the data is all immutable already, no sense in tagging it immutable. I really see use in allowing const. inout is sketchy, I'm trying to think of how this applies, since inout is really for data types that are varied in their constancy. A function has only one addressable instance. shared, well... I don't think we need it. Function stacks shouldn't be shared. One thing you CAN do as a workaround, is put all your data to return into a static struct, and return delegates that address your data: auto foo() { static struct Storage { int x = 4; pure int dg() immutable { return x * x;} // should be strong-pure } immutable(Storage) s; auto d = &s.dg; // I *think* this allocates a closure, but if not, that's a bug. writeln(d()); // s.x = 5; // invalid return d; } Really, a delegate on a function stack is like a single-instance private-defined struct like written above. -SteveThe benefit of tagging it immutable would be to require the delegate to always have an immutable context, for instance, I am accepting a delegate as an argument to a function, but currently right now I have no way to guarantee that the context i receive is immutable. If it was marked immutable, then the supplier of the delegate would be forced to use only immutable things in the context. That's the primary benefit I see. ie: void doSomethingWithDelegate(int delegate() pure nogc safe nothrow immutable del) That actually compiles, but it will only accept delegates to member functions. ._. I dont really know enough about shared and inout to comment on if they could be useful, I only mentioned them because you can put them on member functions.
Jul 01 2015