digitalmars.D.bugs - [Issue 2939] New: lazy evaluation not invoked for lambda function
- d-bugmail puremagic.com (39/39) May 04 2009 http://d.puremagic.com/issues/show_bug.cgi?id=2939
- d-bugmail puremagic.com (19/19) May 04 2009 http://d.puremagic.com/issues/show_bug.cgi?id=2939
- d-bugmail puremagic.com (5/5) May 04 2009 http://d.puremagic.com/issues/show_bug.cgi?id=2939
- d-bugmail puremagic.com (14/16) May 04 2009 http://d.puremagic.com/issues/show_bug.cgi?id=2939
- d-bugmail puremagic.com (7/7) May 05 2009 http://d.puremagic.com/issues/show_bug.cgi?id=2939
- d-bugmail puremagic.com (35/35) May 05 2009 http://d.puremagic.com/issues/show_bug.cgi?id=2939
- d-bugmail puremagic.com (9/17) May 05 2009 http://d.puremagic.com/issues/show_bug.cgi?id=2939
- d-bugmail puremagic.com (9/30) May 05 2009 http://d.puremagic.com/issues/show_bug.cgi?id=2939
- d-bugmail puremagic.com (12/12) May 05 2009 http://d.puremagic.com/issues/show_bug.cgi?id=2939
- d-bugmail puremagic.com (8/9) May 06 2009 http://d.puremagic.com/issues/show_bug.cgi?id=2939
http://d.puremagic.com/issues/show_bug.cgi?id=2939 Summary: lazy evaluation not invoked for lambda function Product: D Version: 2.029 Platform: PC OS/Version: Windows Status: NEW Severity: normal Priority: P2 Component: DMD AssignedTo: bugzilla digitalmars.com ReportedBy: cristian zerobugs.org The following code illustrates how a lambda function is not evaluated when the caller is inside of a foreach block. class X { int bogus; int opApply(int delegate(ref X) dg) { return dg(this); } } void f(lazy void dg) { dg(); } void main() { bool ok = false; void okay() { ok = true; } X x = new X; foreach(elem; x) { f({ok = true;}); // ASSERTION WILL FAIL FOR LAMBDA //f (okay); // works okay for other functions } assert(ok); } --
May 04 2009
http://d.puremagic.com/issues/show_bug.cgi?id=2939 The foreach loop is actually not important. void f(lazy void dg) { dg(); } void main() { void foo() { Stdout.formatln("o hai"); } f(foo); f({Stdout.formatln("lol wut");}); } Only 'o hai' is printed, 'lol wut' never makes it. In order to make it work, you have to put parens after the lambda: f({Stdout.formatln("lol wut");}()); I'm not justifying the compiler's behavior :{ but that's the workaround I've been using. --
May 04 2009
http://d.puremagic.com/issues/show_bug.cgi?id=2939 Also, this happens in D1 as well. I'm never clear on what should be done with the bug versions in these cases.. --
May 04 2009
http://d.puremagic.com/issues/show_bug.cgi?id=2939 clugdbug yahoo.com.au changed: What |Removed |Added ---------------------------------------------------------------------------- Version|2.029 |1.042Also, this happens in D1 as well. I'm never clear on what should be done with the bug versions in these cases..It should be set to D1. Most D1 bugs also apply to D2; the converse is not true. Actually I think it'd be much more useful if the version identifier only had "D1", "D2". (and maybe "D1&D2" or similar). The mass of values are a nuisance, you have to keep updating your searches if you want to look for only D1 bugs, for example. --
May 04 2009
http://d.puremagic.com/issues/show_bug.cgi?id=2939 Here's a proposed fix: in expression.c, at line 693 (using 2.029 as a reference) add a check to see if arg is already a delegate: if (arg->type->ty != Tdelegate) // <---- ADD THIS CHECK arg = arg->toDelegate(sc, p->type); --
May 05 2009
http://d.puremagic.com/issues/show_bug.cgi?id=2939 I think this is working correctly: take this example: import std.stdio; void fn(lazy int i) { writef("%d\n", k); auto j = i(); writef("%d\n", k); auto h = i(); writef("%d\n", k); } int k = 0; void main() { writef("%d\n", k); fn(k++); writef("%d\n", k); } output: 0 0 1 2 2 What is happening in the original cases is that the 'dg();' is evaluating *to the* lambda rather than *evaluating* the lambda. And this is correct as the expression that f was called with is the lambda. (If there is a problem here is it the old one of the skipping the perens on void functions thing) To look at it another way, dg is (almost): delegate void(){ return delegate void(){ ok = true; } } (it's got to play around a bit with context pointers and whatnot but that's side issue) --
May 05 2009
http://d.puremagic.com/issues/show_bug.cgi?id=2939What is happening in the original cases is that the 'dg();' is evaluating *to the* lambda rather than *evaluating* the lambda. And this is correct as the expression that f was called with is the lambda. (If there is a problem here is it the old one of the skipping the perens on void functions thing) To look at it another way, dg is (almost): delegate void(){ return delegate void(){ ok = true; } }Yes, I'm pretty sure that's what's happening. But there are two issues: (1) It's extremely counterintuitive, easy to forget, and when you invariably get bitten by it, the compiler and runtime give no help diagnosing the problem. (2) Why does passing a delegate reference work, but not a lambda? They are *the same type* and you'd expect the compiler to do *the same thing* with both. --
May 05 2009
http://d.puremagic.com/issues/show_bug.cgi?id=2939fair enough complaintWhat is happening in the original cases is that the 'dg();' is evaluating *to the* lambda rather than *evaluating* the lambda. And this is correct as the expression that f was called with is the lambda. (If there is a problem here is it the old one of the skipping the perens on void functions thing) To look at it another way, dg is (almost): delegate void(){ return delegate void(){ ok = true; } }Yes, I'm pretty sure that's what's happening. But there are two issues: (1) It's extremely counterintuitive, easy to forget, and when you invariably get bitten by it, the compiler and runtime give no help diagnosing the problem.(2) Why does passing a delegate reference work, but not a lambda? They are *the same type* and you'd expect the compiler to do *the same thing* with both.I can't prove it but I'd bet this is the same thing: the expression "okay" is begin converted to "okay()" via the no perens rule. so for dg on the inside you get: delegate void(){ okay(); } --
May 05 2009
http://d.puremagic.com/issues/show_bug.cgi?id=2939 I was able to test that my fix works: // Convert lazy argument to a delegate if (p->storageClass & STClazy) { if (arg->type->ty != Tdelegate) // DO NOT "DELEGATIZE" TWICE arg = arg->toDelegate(sc, p->type); } It is a trivial one-liner patch but this bug needs to be voted up to make it to Walter's radar! --
May 05 2009
http://d.puremagic.com/issues/show_bug.cgi?id=2939if (arg->type->ty != Tdelegate) // DO NOT "DELEGATIZE" TWICEPlease no! I don't think this is the correct way to fix this as it is changing the wrong behavior. The correct solution would be to alter the 'no perens on void calls' thing, maybe just in this case. --
May 06 2009