Thread overview |
---|
May 05, 2009 [Issue 2939] New: lazy evaluation not invoked for lambda function | ||||
---|---|---|---|---|
| ||||
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 05, 2009 [Issue 2939] lazy evaluation not invoked for lambda function | ||||
---|---|---|---|---|
| ||||
Posted in reply to d-bugmail | http://d.puremagic.com/issues/show_bug.cgi?id=2939 ------- Comment #1 from jarrett.billingsley@gmail.com 2009-05-05 00:16 ------- 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 05, 2009 [Issue 2939] lazy evaluation not invoked for lambda function | ||||
---|---|---|---|---|
| ||||
Posted in reply to d-bugmail | http://d.puremagic.com/issues/show_bug.cgi?id=2939 ------- Comment #2 from jarrett.billingsley@gmail.com 2009-05-05 00:17 ------- Also, this happens in D1 as well. I'm never clear on what should be done with the bug versions in these cases.. -- |
May 05, 2009 [Issue 2939] lazy evaluation not invoked for lambda function | ||||
---|---|---|---|---|
| ||||
Posted in reply to d-bugmail | http://d.puremagic.com/issues/show_bug.cgi?id=2939 clugdbug@yahoo.com.au changed: What |Removed |Added ---------------------------------------------------------------------------- Version|2.029 |1.042 ------- Comment #3 from clugdbug@yahoo.com.au 2009-05-05 00:36 ------- (In reply to comment #2) > Also, 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 05, 2009 [Issue 2939] lazy evaluation not invoked for lambda function | ||||
---|---|---|---|---|
| ||||
Posted in reply to d-bugmail | http://d.puremagic.com/issues/show_bug.cgi?id=2939 ------- Comment #4 from cristian@zerobugs.org 2009-05-05 02:24 ------- 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 [Issue 2939] lazy evaluation not invoked for lambda function | ||||
---|---|---|---|---|
| ||||
Posted in reply to d-bugmail | http://d.puremagic.com/issues/show_bug.cgi?id=2939 ------- Comment #5 from shro8822@vandals.uidaho.edu 2009-05-05 12:36 ------- 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 [Issue 2939] lazy evaluation not invoked for lambda function | ||||
---|---|---|---|---|
| ||||
Posted in reply to d-bugmail | http://d.puremagic.com/issues/show_bug.cgi?id=2939 ------- Comment #6 from jarrett.billingsley@gmail.com 2009-05-05 14:52 ------- (In reply to comment #5) > 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; } } 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 [Issue 2939] lazy evaluation not invoked for lambda function | ||||
---|---|---|---|---|
| ||||
Posted in reply to d-bugmail | http://d.puremagic.com/issues/show_bug.cgi?id=2939 ------- Comment #7 from shro8822@vandals.uidaho.edu 2009-05-05 15:16 ------- (In reply to comment #6) > (In reply to comment #5) > > > 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; } } > > 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. fair enough complaint > > (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 06, 2009 [Issue 2939] lazy evaluation not invoked for lambda function | ||||
---|---|---|---|---|
| ||||
Posted in reply to d-bugmail | http://d.puremagic.com/issues/show_bug.cgi?id=2939 ------- Comment #8 from cristian@zerobugs.org 2009-05-05 21:58 ------- 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 06, 2009 [Issue 2939] lazy evaluation not invoked for lambda function | ||||
---|---|---|---|---|
| ||||
Posted in reply to d-bugmail | http://d.puremagic.com/issues/show_bug.cgi?id=2939 ------- Comment #9 from shro8822@vandals.uidaho.edu 2009-05-06 16:06 ------- (In reply to comment #8) > if (arg->type->ty != Tdelegate) // DO NOT "DELEGATIZE" TWICE Please 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. -- |
Copyright © 1999-2021 by the D Language Foundation