Scope and Shadowing

(This page just shows code similar to what was used in class. The lecture slides have a more systematic explanation of variable scope and shadowing.)

Scope

You can define a variable inside a function, or at the “top level” of the program (outside of any function).

Variables that are defined inside a function are local to that function. Variables that are defined at the top level are global variables.

(The code that defines a variable is the code that uses the word let, var, or const.)

let x = 10;  // x is a global variable

function setup() {
	let y = 20; // y is local to setup()
}

Code in a function can use local variables and global variables. But code in one function can't see local variables that are defined in another function.

let x = 10;

function setup() {
	createCanvas(windowWidth, windowHeight);
	let y = 20;
	circle(x, y, 10); // this works
}

function draw() {
	square(x, 0, 10); // this works
	square(0, y, 10); // this produces an error.
	// There is no variable named y in this function, and there is no global
	// variable named y.
}

Code in one function can't even see variables in a function that is calling it.

function setup() {
	createCanvas(windowWidth, windowHeight);
}

function draw() {
	let x = 10;
	myShape();
}

function myShape() {
	square(x, 0, 10);  // error. No local or global variable named x
}

Use a parameter to get a variable one function to another.

function setup() {
	createCanvas(windowWidth, windowHeight);
}

function draw() {
	let x = 10;
	myShape(x);
}

function myShape(x) {
	square(x, 0, 10);
}

Or make the function global.

let x = 10;

function setup() {
	createCanvas(windowWidth, windowHeight);
}

function draw() {
	myShape();
}

function myShape() {
	square(x, 0, 10);
}

Shadowing

If there is a local variable and a global variable, the variable name refers to the local variable. It can't “see” the global variable.

let x = 10;

function draw() {
	let x = 20;
	square(x, x, 10);  // draws a rectangle at (20, 20).
}

P5 provides a function named scale.

If you define a variable named scale, you won't be able to use the P5 variable. This will work:

function draw() {
	let scale = 10;
	square(0, 0, scale);
}

But this produces a weird error:

function draw() {
	let scale = 10;
	scale(2, 3);
	square(0, 0, 1);
}

The error is because the code is trying to use 10 as a function (which it is not). It is as though the code were written this way:

function draw() {
	10(2, 3);
	square(0, 0, 1);
}

The Error in Class

Here's one way to define multiple variables:

let x = 10;
let y = 20;

You can also use a single statement to define several variables:

let x = 10, y = 20;

Instead of defining x and y, let's define y and z:

	let y = map(sin(x / 100), -1, 1, 0, height), z = 0;

This defines two variables, y and z. y has initial value that is computed from x and height. z is initialized to the value 0.

Now let's rename zto rect. The new variable rect shadows the p5 function named rect. It's not a very reasonable thing to do, but JavaScript and p5 won't stop us. We just can't use rect() as a function later in function that defines rect as a local variable.

	let y = map(sin(x / 100), -1, 1, 0, height), rect = 0;

Now let's look at the code that I wrote in class, that ended the first line with a comma instead of a semicolon.

	let y = map(sin(x / 100), -1, 1, 0, height),
	rect(x, y, 1, 1);

Until you get to the ( on the second line, this looks like the previous statement, that defines y and rect. However, it is only valid JavaScript if the second line continues as either rect; (to define a variable rect with no explicit initial value), or rect = (to specify the initial value for rect). That's why the error message complained that the second line was missing an =, instead of that the first line ended with a comma instead of a semicolon.