# Variables from higher scope

if i have

why cant i put

it works if y was a global variable, but variables declared in a local scope are lost on the way down.

Because a variable inside a custom block can't access script vars of the script running it, otherwise you'd run into issues with recursion. You'd have to have y as an input in the grey ring, and then it would work.

var y;

var inner = (x) => x + y;

for (y = 0; y < 10; y++) {
console.log(inner(5));
}


returns

5
6
7
.
.
.
13
14


y is declared outside of the function, is not passed into the function, yet still is being used by the inner function.

otherwise in this case it would work. you will run into issues when you write bad code. if theres such an issue an error should be thrown.

Some of Snap still has it's old Scratch roots philosophy of not throwing an error when the programmer makes a mistake

You're using a lamda in your code, not defining a function to return a lamba. You see, custom blocks in snap, are the equivalent of functions in any other language. Grey rings are lambas. In your code, you're only setting the variable inner to a lamda. If you define a function that reports the lamda, it might not give the same results. Also, snap's way of defining the context the variable is in, isn't the same for any other language. For example, variables from the my ([blocks] list need to be asked to a sprite to be put into context, you can't just call it (which I still don't get).

Oh, and just so you might understand what I'm talking about with variables, just try this

Sorry if this doesn't make sense.

edit: actually after thinking about it more, I just realized, you need to think of a custom block as it's own script, and yes, reported lamdas with variables in it, keep the context they were originally created in, the custom block script. If a script var without the var name doesn't exist in the script, it looks for global variables. Getting the value from a variable in a lamda goes back to my project I showed. If you pass a variable in a lamda (grey ring) to another script, it sets the variable in it's original script, not the script that runs it.

Yes this is complicated, I know. I'm trying to understand how to explain it to myself. Maybe @bh could explain it better.

Snap! is lexically scoped, like Scheme and Javascript, not dynamically scoped, like Logo and some early versions of Lisp and Smalltalk.

I don't have the energy right now for a long explanation of the difference, but basically, if you use dynamic scope, which is what @cameron8299 wants, then each invocation of a script with free variables might get those variables from different places -- a global variable if there is one, or a local variable of the procedure that happens to be calling this script this time. Whereas with lexical scope you know where those free variables will come from just by looking at this script and seeing what other scripts, if any, physically contain it.

These days pretty much every programming language is lexically scoped. Logo isn't because there are arguments why a language for kids is easier to understand and use with dynamic scope. Until fairly recently C and some of its children were lexically scoped in the trivial sense that a procedure could see only its own local variables, and global variables, because there was no way to put a procedure definition inside another one. (Now C has lambda, like grownup languages.) Python tries for lexical scope but doesn't get it quite right.

then why does the example I put above, in javascript, seem to do the thing I want, whereas snap doesn't? is that not dynamic scope?

or maybe you could show me the snap equivalent? I don't see how snap and JavaScript have the same kind of scope

I’m guessing it’s because JavaScript recognizes the y variable is declared in the same scope as the “inner” function. But if you declare the y variable in a different scope, like with an IIFE, it won’t work.

In JS, a VAR that's not inside a block makes a global variable. There's really no Snap! equivalent, but imagine if you could put a SCRIPT VARIABLES block all by itself in the scripting area and clicking on it meant to create a global.

I guess you could make a Snap! equivalent to your JS code if you load the variables library and instead of SCRIPT VARIABLES you used

I'm guessing that the difference is partly motivated by the fact that our SCRIPT VARIABLES has "script" in its name, whereas "var" doesn't say what the scope should be, so they wanted it to do something when it's not inside a script.