D issues are now tracked on GitHub. This Bugzilla instance remains as a read-only archive.
Issue 3995 - Can't access array/AA from function literal defined inside the array/AA's initializer
Summary: Can't access array/AA from function literal defined inside the array/AA's ini...
Status: RESOLVED INVALID
Alias: None
Product: D
Classification: Unclassified
Component: dmd (show other issues)
Version: D2
Hardware: All All
: P2 enhancement
Assignee: No Owner
URL:
Keywords: rejects-valid
Depends on:
Blocks:
 
Reported: 2010-03-20 12:38 UTC by Nick Sabalausky
Modified: 2015-06-09 05:11 UTC (History)
1 user (show)

See Also:


Attachments

Note You need to log in before you can comment on or make changes to this issue.
Description Nick Sabalausky 2010-03-20 12:38:04 UTC
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 Nick Sabalausky 2010-03-20 12:48:27 UTC
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 yebblies 2012-02-01 19:07:15 UTC
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 yebblies 2012-02-14 21:42:09 UTC
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.