Bug 3995 – Can't access array/AA from function literal defined inside the array/AA's initializer
Status
RESOLVED
Resolution
INVALID
Severity
enhancement
Priority
P2
Component
dmd
Product
D
Version
D2
Platform
All
OS
All
Creation time
2010-03-20T12:38:00Z
Last change time
2015-06-09T05:11:57Z
Keywords
rejects-valid
Assigned to
nobody
Creator
bus_dbugzilla
Comments
Comment #0 by bus_dbugzilla — 2010-03-20T12:38:04Z
I find this idiom very useful, particularly for handling domain-specific languages:
------------------------------
auto dgMap = [
"foo": (int i) {
return /+..stuff..+/;
},
"bar": (int i) {
return /+..stuff..+/;
},
"bat": (int i) {
return /+..stuff..+/;
},
];
dgMap["bar"](4);
------------------------------
However, those functions cannot refer to each other or use recursion even though doing so would be perfectly safe:
------------------------------
auto dgMap = [
"foo": (int i) {
if(i < 1)
return 0;
else
// Recursion, would be perfectly safe if allowed.
// ERROR: undefined identifier dgMap
return dgMap["foo"](i-1);
},
"bar": (int i) {
// Call different element: would be perfectly safe if allowed.
// ERROR: undefined identifier dgMap
return dgMap["foo"](7);;
}
];
------------------------------
This is a bit of a pain, as it can't be solved without giving up either the locality of the in-line delegate literals or the type inference of the array/AA (which is *very* useful in this sort of situation).
I'm not sure if this counts as an enhancement or a declaration-order bug.
Comment #1 by bus_dbugzilla — 2010-03-20T12:48:27Z
The above example might have a problem inferring the return type of the delegate literals (and therefore the type of 'dgMap' itself). But this alteration doesn't have that problem and still fails to compile with "undefined identifier dgMap":
---------------------
auto dgMap = [
"foo": delegate int(int i) {
if(i < 1)
return 0;
else
return dgMap["foo"](i-1);
},
"bar": delegate int(int i) {
return dgMap["foo"](7);;
}
];
---------------------
Comment #2 by yebblies — 2012-02-01T19:07:15Z
This is working as intended.
Variables are not added to the scope until after their initializers are processed, preventing garbage like this:
int x = x;
And other cases where this would make it possible to refer to uninitialized variables that, even when they have an initializer.
A trivial workaround is the following:
int delegate(int)[string] dgMap;
auto tmp = [ ... delegate definitions referring to dgMap ... ];
dgMap = tmp;
Comment #3 by yebblies — 2012-02-14T21:42:09Z
I think this is invalid, letting the initializer reference the variable is a real pain in c++, and was intentionally disallowed in D.
While it can be useful in some cases (when used carefully) I doubt it's worth adding (for this case or in general), especially when there's such a trivial workaround.
Nick, please reopen if you disagree.