I'm going to assume you mean closures as in Scheme, not closures in a pure functional language.
For that, what I would try is an operational approach:
"Joe, you know how local variables are allocated on a stack?" If he says "no" I'm not sure what the next move is but if he says yes, get him to briefly explain it back to you. E.g., get him to say, at least in vague terms, that on entry to some function the local variables get "pushed on the stack".
"Ok, good. So, what happens when the function returns?" Hopefully he can come up with "the variables are popped off the stack".
"Right. Now, how does the program find the variables on the stack?" Hopefully, Joe can come up with the idea of a stack pointer.
"Cool. [Draw a little picture] So, the stack pointer is kind of like a pointer to a structure. The variables are the fields of the structure. See?" Hopefully Joe says "yes".
"Here's an alternative: instead of using a stack, we could allocate that structure just like any other structure. Instead of popping things off the stack at the end, we could just free/delete/whatever the structure. Make sense?" Hopefully he's still with you.
"Only, we don't actually have to free/delete the structure right away. Suppose I write a function inside this other function, like this [write pseudo-code for an anonymous function with some free variables bound to locals. Have the containing function return this anonymous function.]"
"You might think that when we return a 'function pointer' that we're just returning a pointer to the code. But in this case, our 'function pointer' is really two pointers: a pointer to the code and another pointer to the structure containing the local variables it refers to. So now, we DON'T free/delete that structure of local variables when returning. It sticks around. It's used by this 'function pointer' where returning. When we call that function pointer, it gets passed a sekrit hidden magic parameter which is a pointer to that structure. So the function can still keep using those variables." Hopefully Joe is still with you but ask some questions to find out.
"It's a little bit like that structure of local variables is an object, but an object with only one 'method' and that one method is the nested function we wrote. Get it?"
I think that should get a typical Joe (at least one who has some clue about stacks and stack pointers) to a first-level, rough and ready, operational understanding of closures. If it does, you can mention that actual optimized implementations tend to be a lot hairier, that GC is important, that there are deep connections to lambda calculus, etc.
Again, if on the other hand Joe doesn't even have the slightest awareness of an operational model of how a stack-based language works - I'm not sure what you can do for him.
For that, what I would try is an operational approach:
"Joe, you know how local variables are allocated on a stack?" If he says "no" I'm not sure what the next move is but if he says yes, get him to briefly explain it back to you. E.g., get him to say, at least in vague terms, that on entry to some function the local variables get "pushed on the stack".
"Ok, good. So, what happens when the function returns?" Hopefully he can come up with "the variables are popped off the stack".
"Right. Now, how does the program find the variables on the stack?" Hopefully, Joe can come up with the idea of a stack pointer.
"Cool. [Draw a little picture] So, the stack pointer is kind of like a pointer to a structure. The variables are the fields of the structure. See?" Hopefully Joe says "yes".
"Here's an alternative: instead of using a stack, we could allocate that structure just like any other structure. Instead of popping things off the stack at the end, we could just free/delete/whatever the structure. Make sense?" Hopefully he's still with you.
"Only, we don't actually have to free/delete the structure right away. Suppose I write a function inside this other function, like this [write pseudo-code for an anonymous function with some free variables bound to locals. Have the containing function return this anonymous function.]"
"You might think that when we return a 'function pointer' that we're just returning a pointer to the code. But in this case, our 'function pointer' is really two pointers: a pointer to the code and another pointer to the structure containing the local variables it refers to. So now, we DON'T free/delete that structure of local variables when returning. It sticks around. It's used by this 'function pointer' where returning. When we call that function pointer, it gets passed a sekrit hidden magic parameter which is a pointer to that structure. So the function can still keep using those variables." Hopefully Joe is still with you but ask some questions to find out.
"It's a little bit like that structure of local variables is an object, but an object with only one 'method' and that one method is the nested function we wrote. Get it?"
I think that should get a typical Joe (at least one who has some clue about stacks and stack pointers) to a first-level, rough and ready, operational understanding of closures. If it does, you can mention that actual optimized implementations tend to be a lot hairier, that GC is important, that there are deep connections to lambda calculus, etc.
Again, if on the other hand Joe doesn't even have the slightest awareness of an operational model of how a stack-based language works - I'm not sure what you can do for him.