DEV Community

tang
tang

Posted on

Teaching Functions and Scope With Inception

This one's gonna be a bit rambly. It's still very raw and I'm excited/energized by it, and not totally sure how to structure it, but here goes:

I was at a Codesmith workshop about recursion. I didn't really understand how it passed values outside of the nested bits of it, but finally had the revelation that the return statement continuously kicks a result up a level, only to be returned by the return statement in the nested function before it.

Because I had seen Inception, I was given a very sexy, very exciting way to visualize it; it was exactly like the climactic scene where all of the "waking up" experiences were beautifully synchronized.

I figured I'd rewatch Inception and see what else I could get from it, and I wasn't disappointed.

We can think of the Architect / the Dreamer as a function definition. The Architect sets parameters and defines behavior. The Subject gets passed into the dream, in a similar way that an argument is fed into a function.

What happens when you add a level to a dream / call a function? let's take some kind of f(x) as an example.

When you call a function, you create a local scope, a new world within your existing world (a dream). It comes with local execution context (where things happen) and local memory, which stores local definitions for variables and functions that are either passed into the function, or declared within it. When it finishes running all the code inside of it, it disappears. You wake up. Simple enough, right?

Well, let's fuck things up a little. Remember, we can call functions from inside of other functions right? Higher order functions call lower order functions. There's your dream-within-a-dream. We call the function, and the same thing happens again, just nested one level deeper. f(g(x)), or (f∘g)(x) for those of you familiar with function composition.

A second local execution context (dream-within-a-dream) opens inside of the first local execution context (dream), which exists in the global execution context (reality). Whatever arguments were passed into the 2nd-level from the 1st level are now stored in the local memory of the 2nd-level nested function.

//global scope out here
f(x){
    //local scope 1 / dream 1 here
    some code...

    //and here's where our protagonists whip out the briefcase and stick themselves with the IV to call another function and establish another level to the dream.
    g(x)
}
Enter fullscreen mode Exit fullscreen mode

Then, obviously, it's trivial to go the next level

// "reality" is out here in the global scope
f(x){
    // dream level 1 (the van chase) is here inside of f(x), or the first function
    g(x){
        // dream level 2 (the hotel) is here inside of g(x), or the second nested function
        h(x){
            // and then we have dream level 3, the snowbase.
        }
    }
}
Enter fullscreen mode Exit fullscreen mode

The snow base (dream level 3) needs to resolve before the hotel can resolve (dream level 2), which needs to resolve before the van-chase can resolve (dream level 1), then it'll kick us out to the global execution context (reality). In Inception it happens simultaneously, but in synchronous programming, each expression is evaluated in order until it needs to wait for the next expression to be resolved. f(g(h(x))) resolves f(x) until it hits the part where it needs to resolve g(x), etc etc.

Ultimately, the answer that we get at h(x) (dream level 3) is the one that enables us to resolve the expressions all the way up.

What allows us to do this is the "kick", where we're able to send people back out of a dream without losing the information they've gotten. In our case, that's done with return statements.

// "reality" is out here in the global scope
f(x){
    // dream level 1 (the van chase) is here inside of f(x), or the first function
    return g(x){
        // dream level 2 (the hotel) is here inside of g(x), or the second nested function
        return h(x){
            // and then we have dream level 3, the snowbase.
        }
    }
}
Enter fullscreen mode Exit fullscreen mode

If we don't return anything from our functions by the end of running them, the local scope closes, and everything stored in local memory gets tossed out/garbage collected. I suppose we could imagine that this is "limbo", except that in Inception, you can actually get out of it pretty easily. Not so for us.

That's about as far as I've gotten with it, and, honestly, if you understand Inception, you probably do understand scope and recursion to begin with, but maaaaaaaaaybe this is something that could be used as a teaching tool in some way.

Top comments (0)