digitalmars.D - weird behavior returning delegate
- Carlos Santander (49/49) Jul 01 2006 This code, with DMD 0.162 on Windows:
- Sean Kelly (7/67) Jul 01 2006 It's because you're using one function to do the asserts and another to
- Carlos Santander (10/81) Jul 01 2006 I did the same too, but that's what I don't understand: what are really ...
- Sean Kelly (13/31) Jul 01 2006 When you enter the realm of undefined behavior, anything goes. In this
- Carlos Santander (6/44) Jul 02 2006 Thanks for the answers. I was hoping D could be added to
- Tom S (21/24) Jul 02 2006 It's not very bad in D:
- Chris Nicholson-Sauls (18/48) Jul 02 2006 Or even this:
- Bruno Medeiros (8/22) Jul 03 2006 Nope, even if the static variable were to be initialized at delegate
- Chris Nicholson-Sauls (6/29) Jul 03 2006 True enough. If 'n' were part of the template's parameters then it woul...
- Tom S (18/18) Jul 03 2006 Or for the extremists...
- John Reimer (3/26) Jul 03 2006 Bad, Tom. You've been playing with templates again, haven't you? ;)
- Tom S (5/6) Jul 03 2006 But ... but ... um ... I'm sorry :( /* crosses fingers */ I promise I'll...
- Bruno Medeiros (12/41) Jul 03 2006 Also, if something like Markus Dangl partial application were available
This code, with DMD 0.162 on Windows: //----------------------- T delegate (T) acc (T) (T n) { return (T i) { return n += i; }; } void foo () { auto acc1 = acc (4); assert (5 == acc1 (1), "5 != 5"); assert (7 == acc1 (2), "7 != 7"); auto acc2 = acc (10); assert (11 == acc2 (1), "11 != 11"); assert (12 == acc2 (1), "12 != 12"); assert (10 == acc1 (3), "10 != 10"); // 16 assert (20 == acc2 (8), "20 != 20"); } import std.stdio; void bar () { auto acc1 = acc (4); writefln (" 5 == %s", acc1 (1)); writefln (" 7 == %s", acc1 (2)); auto acc2 = acc (10); writefln ("11 == %s", acc2 (1)); writefln ("12 == %s", acc2 (1)); writefln ("10 == %s", acc1 (3)); writefln ("20 == %s", acc2 (8)); writefln (); } void main() { bar (); foo (); } //----------------------- Produces this: 5 == 5 7 == 10 11 == 11 12 == 9 10 == 13 20 == 17 Error: AssertError Failure test.d(16) 10 != 10 I think the assert failing is somewhat expected (stack frame no longer available), but how can the previous asserts work when the values shown with writefln are not the ones expected, or supposedly asserting correctly? -- Carlos Santander Bernal
Jul 01 2006
Carlos Santander wrote:This code, with DMD 0.162 on Windows: //----------------------- T delegate (T) acc (T) (T n) { return (T i) { return n += i; }; } void foo () { auto acc1 = acc (4); assert (5 == acc1 (1), "5 != 5"); assert (7 == acc1 (2), "7 != 7"); auto acc2 = acc (10); assert (11 == acc2 (1), "11 != 11"); assert (12 == acc2 (1), "12 != 12"); assert (10 == acc1 (3), "10 != 10"); // 16 assert (20 == acc2 (8), "20 != 20"); } import std.stdio; void bar () { auto acc1 = acc (4); writefln (" 5 == %s", acc1 (1)); writefln (" 7 == %s", acc1 (2)); auto acc2 = acc (10); writefln ("11 == %s", acc2 (1)); writefln ("12 == %s", acc2 (1)); writefln ("10 == %s", acc1 (3)); writefln ("20 == %s", acc2 (8)); writefln (); } void main() { bar (); foo (); } //----------------------- Produces this: 5 == 5 7 == 10 11 == 11 12 == 9 10 == 13 20 == 17 Error: AssertError Failure test.d(16) 10 != 10 I think the assert failing is somewhat expected (stack frame no longer available), but how can the previous asserts work when the values shown with writefln are not the ones expected, or supposedly asserting correctly?It's because you're using one function to do the asserts and another to print results, so the values returned from acc1 and acc2 may be different. I combined the two cases by storing the result in a number then performing the assert, etc, and the errors corresponded with what was displayed. Sean
Jul 01 2006
Sean Kelly escribió:Carlos Santander wrote:I did the same too, but that's what I don't understand: what are really the correct values, the ones that are printed or the ones that pass the asserts? Also, I don't think putting them in one, two or more functions really matters. I would expect the previous acc1 and acc2 to be gone when the function exits. Anyway, bottom line is I think I'm hoping for too much. Unless something like Burton's proposed "new delegate" syntax is put into the language, this wouldn't really work properly. -- Carlos Santander BernalThis code, with DMD 0.162 on Windows: //----------------------- T delegate (T) acc (T) (T n) { return (T i) { return n += i; }; } void foo () { auto acc1 = acc (4); assert (5 == acc1 (1), "5 != 5"); assert (7 == acc1 (2), "7 != 7"); auto acc2 = acc (10); assert (11 == acc2 (1), "11 != 11"); assert (12 == acc2 (1), "12 != 12"); assert (10 == acc1 (3), "10 != 10"); // 16 assert (20 == acc2 (8), "20 != 20"); } import std.stdio; void bar () { auto acc1 = acc (4); writefln (" 5 == %s", acc1 (1)); writefln (" 7 == %s", acc1 (2)); auto acc2 = acc (10); writefln ("11 == %s", acc2 (1)); writefln ("12 == %s", acc2 (1)); writefln ("10 == %s", acc1 (3)); writefln ("20 == %s", acc2 (8)); writefln (); } void main() { bar (); foo (); } //----------------------- Produces this: 5 == 5 7 == 10 11 == 11 12 == 9 10 == 13 20 == 17 Error: AssertError Failure test.d(16) 10 != 10 I think the assert failing is somewhat expected (stack frame no longer available), but how can the previous asserts work when the values shown with writefln are not the ones expected, or supposedly asserting correctly?It's because you're using one function to do the asserts and another to print results, so the values returned from acc1 and acc2 may be different. I combined the two cases by storing the result in a number then performing the assert, etc, and the errors corresponded with what was displayed. Sean
Jul 01 2006
Carlos Santander wrote:Sean Kelly escribió:When you enter the realm of undefined behavior, anything goes. In this case I think the residual stack data is just a bit different in foo() and bar(), possibly because bar() is called before foo() or simply as an artifact of different code generation, so the calls that break are different in each case.It's because you're using one function to do the asserts and another to print results, so the values returned from acc1 and acc2 may be different. I combined the two cases by storing the result in a number then performing the assert, etc, and the errors corresponded with what was displayed.I did the same too, but that's what I don't understand: what are really the correct values, the ones that are printed or the ones that pass the asserts?Also, I don't think putting them in one, two or more functions really matters. I would expect the previous acc1 and acc2 to be gone when the function exits.Yes but the delegates are referencing invalid stack locations, and so there's no guarantee that the data will be the same even if the basic sequence of calls is similar for both foo() and bar().Anyway, bottom line is I think I'm hoping for too much. Unless something like Burton's proposed "new delegate" syntax is put into the language, this wouldn't really work properly.Yeah. I think it might work if acc() accepted 'n' as 'inout', but doing so still seems a bad idea as the delegate's stack context is technically invalid at the point where it's called by foo() and bar(). Sean
Jul 01 2006
Sean Kelly escribió:Carlos Santander wrote:Thanks for the answers. I was hoping D could be added to http://www.paulgraham.com/accgen.html only with three lines instead of something like that horrible C++ code. -- Carlos Santander BernalSean Kelly escribió:When you enter the realm of undefined behavior, anything goes. In this case I think the residual stack data is just a bit different in foo() and bar(), possibly because bar() is called before foo() or simply as an artifact of different code generation, so the calls that break are different in each case.It's because you're using one function to do the asserts and another to print results, so the values returned from acc1 and acc2 may be different. I combined the two cases by storing the result in a number then performing the assert, etc, and the errors corresponded with what was displayed.I did the same too, but that's what I don't understand: what are really the correct values, the ones that are printed or the ones that pass the asserts?Also, I don't think putting them in one, two or more functions really matters. I would expect the previous acc1 and acc2 to be gone when the function exits.Yes but the delegates are referencing invalid stack locations, and so there's no guarantee that the data will be the same even if the basic sequence of calls is similar for both foo() and bar().Anyway, bottom line is I think I'm hoping for too much. Unless something like Burton's proposed "new delegate" syntax is put into the language, this wouldn't really work properly.Yeah. I think it might work if acc() accepted 'n' as 'inout', but doing so still seems a bad idea as the delegate's stack context is technically invalid at the point where it's called by foo() and bar(). Sean
Jul 02 2006
Carlos Santander wrote:Thanks for the answers. I was hoping D could be added to http://www.paulgraham.com/accgen.html only with three lines instead of something like that horrible C++ code.It's not very bad in D: T delegate(T) acc(T)(T i) { class Foo { T x; this() { x = i; } T func(T a) { return x += a; } } return &(new Foo).func; } or T delegate(T) acc(T)(T i) { auto res = new class Object { T x; T func(T a) { return x += a; } }; res.x = i; return &res.func; } -- Tomasz Stachowiak /+ a.k.a. h3r3tic +/
Jul 02 2006
Tom S wrote:Carlos Santander wrote:Or even this: } } ) { If in delegate literals we could declare static variables initialized from the local frame, then it could even have simply been this: Alas. -- Chris Nicholson-SaulsThanks for the answers. I was hoping D could be added to http://www.paulgraham.com/accgen.html only with three lines instead of something like that horrible C++ code.It's not very bad in D: T delegate(T) acc(T)(T i) { class Foo { T x; this() { x = i; } T func(T a) { return x += a; } } return &(new Foo).func; } or T delegate(T) acc(T)(T i) { auto res = new class Object { T x; T func(T a) { return x += a; } }; res.x = i; return &res.func; }
Jul 02 2006
Chris Nicholson-Sauls wrote:If in delegate literals we could declare static variables initialized from the local frame, then it could even have simply been this: Alas. -- Chris Nicholson-SaulsNope, even if the static variable were to be initialized at delegate literal evaluation time, instead of delegate run time, it wouldn't work as there is only one delegate "body instance", so each accumulator would share the same static var. -- Bruno Medeiros - CS/E student http://www.prowiki.org/wiki4d/wiki.cgi?BrunoMedeiros#D
Jul 03 2006
Bruno Medeiros wrote:Chris Nicholson-Sauls wrote:True enough. If 'n' were part of the template's parameters then it would be a bit closer, as then there would be a seperate function for each starting value... but then you couldn't use 'foo(N)' more than once for any given N. I guess the only way to pull this off is going to be with a class, like the other three examples. Seems like a shame, though. -- Chris Nicholson-SaulsIf in delegate literals we could declare static variables initialized from the local frame, then it could even have simply been this: Alas. -- Chris Nicholson-SaulsNope, even if the static variable were to be initialized at delegate literal evaluation time, instead of delegate run time, it wouldn't work as there is only one delegate "body instance", so each accumulator would share the same static var.
Jul 03 2006
Or for the extremists... T delegate(T a) acc(T)(T i){ struct Foo { T a; T func(T x) { return a += x; } } return &(cast(Foo*)((&i)[0..1]).dup).func; } or... T delegate(T a) acc(T)(T i){ struct Foo { T a; T func(T x) { return a += x; } } return &(cast(Foo*)((new T[1])[] = i)).func; } -- Tomasz Stachowiak /+ a.k.a. h3r3tic +/
Jul 03 2006
Tom S wrote:Or for the extremists... T delegate(T a) acc(T)(T i){ struct Foo { T a; T func(T x) { return a += x; } } return &(cast(Foo*)((&i)[0..1]).dup).func; } or... T delegate(T a) acc(T)(T i){ struct Foo { T a; T func(T x) { return a += x; } } return &(cast(Foo*)((new T[1])[] = i)).func; }Bad, Tom. You've been playing with templates again, haven't you? ;) -JJR
Jul 03 2006
John Reimer wrote:Bad, Tom. You've been playing with templates again, haven't you? ;)But ... but ... um ... I'm sorry :( /* crosses fingers */ I promise I'll be a good boy ;) -- Tomasz Stachowiak /+ a.k.a. h3r3tic +/
Jul 03 2006
Tom S wrote:Carlos Santander wrote:Also, if something like Markus Dangl partial application were available in the library, it could be this as well: T delegate(T) acc(T)(T i) { return &AdvancedDelegate( (T num, T inc) { return num + inc; } ) (i).Eval; } :) -- Bruno Medeiros - CS/E student http://www.prowiki.org/wiki4d/wiki.cgi?BrunoMedeiros#DThanks for the answers. I was hoping D could be added to http://www.paulgraham.com/accgen.html only with three lines instead of something like that horrible C++ code.It's not very bad in D: T delegate(T) acc(T)(T i) { class Foo { T x; this() { x = i; } T func(T a) { return x += a; } } return &(new Foo).func; } or T delegate(T) acc(T)(T i) { auto res = new class Object { T x; T func(T a) { return x += a; } }; res.x = i; return &res.func; }
Jul 03 2006