Thread overview | |||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
July 01, 2006 weird behavior returning delegate | ||||
---|---|---|---|---|
| ||||
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
|
July 01, 2006 Re: weird behavior returning delegate | ||||
---|---|---|---|---|
| ||||
Posted in reply to Carlos Santander | 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
|
July 01, 2006 Re: weird behavior returning delegate | ||||
---|---|---|---|---|
| ||||
Posted in reply to Sean Kelly | Sean Kelly escribió: > 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 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 Bernal |
July 01, 2006 Re: weird behavior returning delegate | ||||
---|---|---|---|---|
| ||||
Posted in reply to Carlos Santander | Carlos Santander wrote: > Sean Kelly escribió: >> >> 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? 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. > 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 |
July 02, 2006 Re: weird behavior returning delegate | ||||
---|---|---|---|---|
| ||||
Posted in reply to Sean Kelly | Sean Kelly escribió: > Carlos Santander wrote: >> Sean Kelly escribió: >>> >>> 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? > > 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. > >> 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 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 Bernal |
July 02, 2006 Re: weird behavior returning delegate | ||||
---|---|---|---|---|
| ||||
Posted in reply to Carlos Santander | 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 +/ |
July 03, 2006 Re: weird behavior returning delegate | ||||
---|---|---|---|---|
| ||||
Posted in reply to Tom S | Tom S wrote:
> 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;
> }
>
Or even this:
# T delegate (T) foo (T) (T n) {
# with ( new class Object { private T x; public T acc (T i) { return x += i; } } ) {
# x = n;
# return &acc;
# }
# }
If in delegate literals we could declare static variables initialized from the local frame, then it could even have simply been this:
# T delegate (T) foo (T) (T n) {
# return (T i) {
# static T x = n ;
# return x += i ;
# };
# }
Alas.
-- Chris Nicholson-Sauls
|
July 03, 2006 Re: weird behavior returning delegate | ||||
---|---|---|---|---|
| ||||
Posted in reply to Tom S | Tom S wrote: > 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; > } > > 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#D |
July 03, 2006 Re: weird behavior returning delegate | ||||
---|---|---|---|---|
| ||||
Posted in reply to Chris Nicholson-Sauls | 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: > > # T delegate (T) foo (T) (T n) { > # return (T i) { > # static T x = n ; > # return x += i ; > # }; > # } > > Alas. > > -- Chris Nicholson-Sauls Nope, 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 |
July 03, 2006 Re: weird behavior returning delegate | ||||
---|---|---|---|---|
| ||||
Posted in reply to Bruno Medeiros | Bruno Medeiros wrote:
> 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:
>>
>> # T delegate (T) foo (T) (T n) {
>> # return (T i) {
>> # static T x = n ;
>> # return x += i ;
>> # };
>> # }
>>
>> Alas.
>>
>> -- Chris Nicholson-Sauls
>
>
> Nope, 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.
>
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-Sauls
|
Copyright © 1999-2021 by the D Language Foundation