Hey all, so I’ve been asked to do something a little more in-depth, and I’ve been given no requests, so I picked closures in Perl.
A closure is a function which was created dynamically inside of another function. In Perl (among other languages), these are sometimes referred to as anonymous subroutines. In Perl, all closures are anonymous subroutines, but not all anonymous subroutines are closures. The key differentiating feature is scope: a closure has access to lexically-scoped variables within a containing subroutine, whereas an anonymous subroutine is not necessarily even inside of a function.
Closures Versus Anonymous Subroutines
Here is an example of an anonymous subroutine:
Notice how this creates a
CODEREF and then executes it. This is essentially just a normal function. To contrast, here is an example of a closure:
Notice how this is a function which returns a
CODEREF, and then when you call that
CODEREF it has access to the
@inputs variable of its containing function.
Why Use Closures?
This of course brings up the question of why you would want to use closures. There are three very common instances where closures are a very good solution:
- When you are doing asynchronous tasks, such as loading data or processing large amounts of data
- When you need to use custom functions to process data (think sorting compare routines)
- When you want to create or consume a library or application where one application’s code interacts directly within the other’s.
Nuts & Bolts
The biggest confusion I had when I was first exposed to closures – way back when – was when does the memory in a variable (like
@inputs above) get reaped by the garbage collector? Well, those variables get reaped whenever anything referencing them gets reaped. That means that after line 8 when we
undef $closure; is when that
@inputs gets reaped.
Prove it, you say? Okay, but first we have to have a way of detecting when a variable is reaped. With OO Perl this is easy, just handle the
DESTROY() method. Here’s a quick example of that type of code:
Now that we have this piece of code we can prove this. Here’s a snippet using the above
DestroyDetector class to demonstrate how the garbage collector:
First we prove that an
undef() call will trigger the
DESTROY() function which prints the message. Then we create a function which returns a closure, which we then exercise. Finally, we undef the variable holding a reference to the closure and we observe the message announcing the destruction of the closure.
Here’s the output:
Announcing DestroyDetector "about to undef foo1" value: foo1 Destroying DestroyDetector value: foo1 Announcing DestroyDetector "Pre-closure definition..." value: closure1 Announcing DestroyDetector "calling from the closure!" value: closure1 Announcing DestroyDetector "About to undef() the closure..." value: closure1 Destroying DestroyDetector value: closure1 You should have just seen the DestroyDetector destroy "closure1".