www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.learn - Nested function requires forward declaration?

reply Chris Katko <ckatko gmail.com> writes:
Using DMD. v2.098-beta-2

Not sure if right terminology. But I just wrote a nested function 
that uses a variable outside its body. The capture (right term?) 
is obvious where the invocation is. However, I have to move the 
declaration of the variable to above the nested function for it 
to compile.

Here is the code that wont compile:
````D
void execute()
	{
	bool isKey(ALLEGRO_KEY key)
		{
		return (event.keyboard.keycode == key);
		}
	ALLEGRO_EVENT event;
	// later
	isKey(ALLEGRO_KEY_W);

// main.d(491): Error: undefined identifier `event`
````

This however, will compile:
````D
void execute()
	{
	ALLEGRO_EVENT event; // <--Only change
	bool isKey(ALLEGRO_KEY key)
		{
		return (event.keyboard.keycode == key);
		}
	// later
	isKey(ALLEGRO_KEY_W);
````

It appears the nested function's variable capture depends on 
forward declaration (the right term?). Whereas, I was under the 
impression most/all of D worked on a multiple pass compilation so 
the order of declarations shouldn't matter.

Is this a D spec, or a compiler parsing error/oversight?

I guess if I had two different variables called event, this could 
become confusing code to read except that, mentally these should 
still link up, right?

Hypothetical:
````D
void execute()
{
bool isKey(ALLEGRO_KEY key)
	{
	return (event.keyboard.keycode == key);
	}

    {
    ALLEGRO_EVENT event;
    isKey(ALLEGRO_KEY_W);
    } //lets say this does some memory housekeeping/deleting so 
that's why we use scope
    {
    ALLEGRO_EVENT event; //new 'event', same name, new memory
    isKey(ALLEGRO_KEY_W);
    }
}
````

in this case, 'event' under-the-hood could be renamed, say, 
"event2" and have the same expected compile time symbol linking 
occur. The second isKey call is obviously connected to the second 
'event' variable.

I imagine this is a really odd edge case but it's piqued my 
interest.
Apr 14 2022
next sibling parent Stanislav Blinov <stanislav.blinov gmail.com> writes:
On Thursday, 14 April 2022 at 08:55:25 UTC, Chris Katko wrote:
 Using DMD. v2.098-beta-2

 Not sure if right terminology. But I just wrote a nested 
 function that uses a variable outside its body. The capture 
 (right term?) is obvious where the invocation is. However, I 
 have to move the declaration of the variable to above the 
 nested function for it to compile.
Declarations in function scope are processed in order. This includes nested functions: https://dlang.org/spec/function.html#nested
Apr 14 2022
prev sibling next sibling parent Mike Parker <aldacron gmail.com> writes:
On Thursday, 14 April 2022 at 08:55:25 UTC, Chris Katko wrote:

 I imagine this is a really odd edge case but it's piqued my 
 interest.
Consider this: ```d void main() { void foo() { initRuntimeState(i); } foo(); if(!modifyRutimeState()) return; int i = getRandomValue(); i = returnSomethingBasedOnRuntimeState(i); } ``` Which value of `i` should `foo` use? What if `modifyRuntimeState` and `returnSomethingBasedOnRuntimeState` are dependent on `initRuntimeState`? At module scope, and in class/struct declarations, only compile-time values can be used to initialize variables and assignment is illegal, so the compiler can jump around initializing things in any order it wants. It has a well-defined and limited set of rules it can work with. That just isn't the case in local scopes, where a variable's lifetime begins at the point of declaration, the scope can exit at any time, and the order of evaluation can have side effects that change the run-time state.
Apr 14 2022
prev sibling parent Salih Dincer <salihdb hotmail.com> writes:
On Thursday, 14 April 2022 at 08:55:25 UTC, Chris Katko wrote:
 [...]
 It appears the nested function's variable capture depends on 
 forward declaration (the right term?). Whereas, I was under the 
 impression most/all of D worked on a multiple pass compilation 
 so the order of declarations shouldn't matter.

 Is this a D spec, or a compiler parsing error/oversight?
 [...]
This is cross-module what you're talking about, eg outside of main(). Something with most programming languages, it's not about nested function. Do it with lambda if you want, and you'll get the same result: ```d /* auto is_Key = (ALLEGRO_KEY key) => (event.keyboard.keycode == key); // Not compiling! */ ALLEGRO_EVENT event; ``` You have one more option, and that is to use OOP. You can even briefly encapsulate it into a struct. SDB 79
Apr 14 2022