[Chicago-talk] The "other" closure

Jim Thomason jthomasoniii at yahoo.com
Wed Dec 3 07:19:05 CST 2003


So things were busy last night and I was on the other
side of the room and didn't want to jump up and sprint
across and chime in.

Anyway, people were asking about closures, and Steve
was explaining things. And it seemed like a few folks
were glazing over, as they always tend to. "Wait, so
it's an anonymous subroutine that has variables that
don't exist? Isn't that an error?" (No, no one asked
that, it's an example). Happens all the time - in
person, on the internet, etc. It's just one of those
things that can take a few instances to click.

That said, there's another type of closure that (I
think)  is easier to understand. Some people are
sticklers and say they're not real closures because
they don't have anonymous subroutines, but I
cheerfully ignore them. In my opinion, the important
bit about a closure is the fact that it refers to a
lexical that can't be accessed from anywhere except
for within the subroutine.

(and, for those new to the terminology, a "lexical"
variable is a "my" variable)

So, with only using that requirement, this is a
closure:

{
  my $static = 0;
  sub foo {
    print STDERR "I've been called ", ++$static, "
times\n";
    #...do interesting things
  }
}

Voila! A closure. $static only exists inside foo(),
you cannot touch it in any way outside of there. Now,
while this example is a little silly, it immediately
shows you about two important things.
1) This is how you can add static variables to a
function. $static here keeps its value from one
invocation to the next, is only visible in the
function, and is very useful to you.
2) You can have bulletproof encapsulation of data.
Personally, I love using this for class methods when
I'm building classes (well, auto-generate that code
instead of re-typing it constantly, but you get the
idea). I'm a real stickler for using the
accessors/mutators for everything, and this is an easy
way to utterly prevent someone from directly accessing
a package variable that you're using as a class
variable. If they want to use it, they *have* to go
through your accessor. No #define private public
nonsense here! Next time you hear someone griping
about perl's OO, point out that perl can encapsulate
data more solidly than just about anything else.

You can also use similar approaches to go completely
bananas and lock up your entire internal object
structure. This is usually more trouble than it's
worth, though.

Anyway, I use this type of closure far more frequently
than the other, more accepted kind. If you're a
stickler for exact definitions, just take a reference
to foo and call that instead.

my $bar = \&foo;

Then $bar is a closure in every sense of the word. It
rarely comes to that for me.

It works the way Steve explained last night. During
compilation, perl enters the block, spots the lexical,
and continues. It enters the subroutine and notes that
it refers to the lexical, leaves the subroutine, and
then leaves the block. Once outside the enclosing
block, the knowledge of the lexical vanishes, but the
subroutine still knows about it.

You can do the exact same thing as the example above
with a goto, but in an effort to avoid things being
thrown at me, I shan't elaborate.

Further, this can also work as a cautionary example of
why using globals and side effects can be a bad thing.
If you get rid of that enclosing block, you'd have:

 my $static = 0;
 sub foo {
   print STDERR "I've been called ", ++$static, "
times\n";
   #...do interesting things
 }

which is definitely not a closure. Other things can
refer to $static and manipulate it and alter your
value, which would screw up your "I've been called..."
output. By stuffing it inside a block (closure!) you
save yourself the headache of worrying about side
effects or other people messing with your variable.
Only you get to touch it.

Just concentrating on "it's a function that sees
otherwise out-of-scope lexicals" let's you worry about
what it does (such as that foo() example up above)
instead of worrying about taking function references
or building lookup tables or whatnot (which you can
worry about later once you're comfortable with the
simpler form listed here). It's quite a useful tool to
be able to pull out of your bag of tricks.

And no, Andy, this is all I care to go into on
closures, I ain't giving a talk on it. :*)

-Jim.....

__________________________________
Do you Yahoo!?
Free Pop-Up Blocker - Get it now
http://companion.yahoo.com/



More information about the Chicago-talk mailing list