JMP Scope -- Dynamic vs. Lexical scope and general confusion learning JSLIf I'm wrong please correct me, but it would seem that JMP has dynamic-scope with no scope persistence (except for the pseudo-namespaces Here, Window, Box). This contrasts with many popular programming languages that have lexical-scope with full scope-persistence using reference-counters.
This caused a lot of head-smashing on my end until I gained the intuition needed to work with the weird scope system that JMP has, and I believe that it's a large point of confusion for many people. Not many programming languages use Dynamic scope (LISP being an important exception, and JSL has some similarities to LISP).
I'd encourage the JSL documentation team to point out this distinction and provide some resources / links on how to better understand Dynamic scope as it certainly is not the standard way of doing name-resolution.
Here is an example -- the outer function's local scope is cleared up immediately after the return statement, and the inner functions name-resolution is dynamic (based on the current call-stack):
Names Default to Here( 1 );
x = 7;
outer function = Function( {},
{x},
x = 4;
inner function = Function( {},
Print( x )
);
Return( Name Expr( inner function ) );
);
func = outer function;
func()
/*** OUTPUT ***
7If you do something functionally equivalent in a lexically-scoped language with scope-persistence (like Python), then the inner function's enclosing-scope is persistent (it's the local-scope for the outer function), and the name-resolution for the inner function's x-variable is the value 4 from the lexical reading of the system. Since JMP doesn't use lexical-scope, but uses dynamic-scope, then when the inner function is finally executed at the end of the script, it uses dynamic name-resolution of Local -> Here -> Global (and possible column-names for the current table) and finds the value 7.
Understanding this type of behavior is critical for building robust programs in JSL, and I just want to point it out to anyone learning / struggling with JSL.
Let me know if you have any thoughts / unintuitive examples!
Automation and ScriptingData AccessRe: JMP Scope -- Dynamic vs. Lexical scope and general confusion learning JSLThis is true, and definitely threw me for a loop when learning the language. The other wrinkle is that JSL is a Term Rewriting Language thanks to its expression objects, which means that while being LISP-ish with respect to scoping, is not LISP-ish with respect to how it handles macros.
The only other term-rewriting language I'm aware of in popular use is Wolfram Language. I'm not well versed enough in CS to say for sure, but I have heard some people allege that the term-rewriting paradigm is strictly more powerful than Lisp's macros. On the other hand, I have heard some claim that Wolfram Language is simply an implementation of m-expressions, where Lisp decided s-expressions were good enough.
Regardless, JSL's expression system will be foreign to just about everyone, and the ergonomics of their functions for working with expressions don't do them any favors. There is a reason that you can find so many examples in this forum of people using string manipulation and Parse() instead of the term-rewriting features.
Re: JMP Scope -- Dynamic vs. Lexical scope and general confusion learning JSLI'm not a CS person myself, but this stuff on term-rewriting is quite interesting! Thanks for the reference, I'll be up all night on this rabbit-hole now...
Re: JMP Scope -- Dynamic vs. Lexical scope and general confusion learning JSLThe
func = outer function;
func();
puzzled me.
After executing
func = outer function();
the definition of inner function is stored in the variable func.
This is why Show(func) returns
func = Function({},Print(x));
At this point, all the information about outer function and inner function is gone.
So func() will execute Print(x) and ... prints 7.
edit:
Actually, there's nothing new compared to what was written in the main post.
Just the "2D view" of a JSL programmer.
Re: JMP Scope -- Dynamic vs. Lexical scope and general confusion learning JSLJMP keeps variables in the function definition as they are - it doesn't replace them automatically with the current value.
So, after
x = 4;
inner function = Function( {}, Print( x ));
inner function is defined as
Function( {}, Print( x ));
To make the inner function replace it's x with the x from the outer function, one needs some pre-evaluation like
Names Default to Here( 1 );
x = 7;
outer function = Function( {},
{x},
x = 4;
Eval(Eval Expr( inner function = Function( {},
x= Expr(x);
Print( x )
)));
Return( Name Expr(inner function));
);
func = outer function;
func() // prints 4
edit: same 2D view with other words.
Re: JMP Scope -- Dynamic vs. Lexical scope and general confusion learning JSLI took a quick look over the fence:
def outer():
y=4
def inner():
print(y)
return inner
f = outer()
y = 7
f() # -> 4
So, Python returns 3. Because this is how y is defined in the lexical context when inner is defined.
"Defined" - or "returned"?
Let's have another look:
def outer():
y=4
def inner():
print(y)
y=-100
return inner
f = outer()
y = 7
f()
-> -100