Web Developer's Virtual Library: Encyclopedia of Web Design Tutorials, Articles and Discussions


WDVL Newsletter

Active Server Pages
JSP/Java Servlets
Microsoft SQL Server
Daily Backup
Dedicated Servers
Streaming Audio/Video
24-hour Support    

jobs.webdeveloper.com

Hiermenus


e-commerce
Partner With Us















Developer Channel
FlashKit.com
JavaScript.com
JavaScriptSource
Developer Jobs
ScriptSearch
StreamingMediaWorld
Web Developer's Journal
Web Developer's Virtual Library
WebDeveloper.com
Webreference
Web Hosts
XMLfiles.com

internet.com
IT
Developer
Internet News
Small Business
Personal Technology

Search internet.com
Advertise
Corporate Info
Newsletters
Tech Jobs
E-mail Offers


Closures - Page 23

July 27, 2001

Closures are subroutines that operate on variables created in the context in which they were defined, rather than passed in or created locally. This means that they manipulate variables outside their own definition, but within their scope. Here is a simple example of a closure at work:

$count = 0;
sub count {return ++ $count;}
print count, count, count; # print 123

Here the subroutine count uses the variable $count. But the variable is defined outside of the subroutine, and so is defined for as long as the program runs. Nothing particularly remarkable so far, all we are doing is defining a global variable. However, what makes closures useful is that they can be used to implement a form of memory in subroutines where the variable is global inside the subroutine, but is invisible outside. Consider the following example:

{
$count = 0;
  sub count {return ++ $count;}
}
print count, count, count; # still print 123

What makes this interesting is that the variable $count is no longer directly accessible by the time we get to the print statement. Ordinarily it would have ceased to exist at the end of the block in which it is defined because it is lexical, and therefore bounded by the block's scope. However, it is referred to in the subroutine count, which is by nature a global definition. Consequently, Perl still has a reference to the variable and so it persists. The only place the reference exists is in the subroutine count, so we have effectively created a persistent and private variable inside count.

Closures get more interesting when we create them in an anonymous subroutine. If we replace the block with a subroutine definition and count with an anonymous subroutine, we end up with this:

sub make_counter ($) {
  $count = shift;
  return sub {return $count++;}
}

The outer subroutine make_counter accepts one scalar variable and uses it to initialize the counter variable. We then create an anonymous subroutine that refers to the variable (thus preserving it) and returns the code reference of the anonymous subroutine. We can now use make_counter to create and use any number of persistent counters, each using its own secret counter variable:

$tick1 = make_counter(0); #counts from zero
$tick2 = make_counter(100); #counts from 100

$, = ",";
print &$tick1, &$tick2, &$tick1, &$tick2;
# displays 0, 100, 1, 101

Just because the subroutine is anonymous does not mean that it cannot accept parameters — we just access the @_ array as normal. Here is a variation of make_counter that allows us to reset the counter variable by passing a number to the anonymous subroutine:

#!/usr/bin/perl
# closure.pl
use warnings;
use strict;

sub make_counter ($) {
  my $count = @_?shift:0;

  return sub {
    $count = $_[0] if @_;
    return $count++;
  }
}

my $counter = make_counter(0);
foreach (1..10) {
  print &$counter, "\n";
}
print "\n"; # displays 0, 1, 2, 3, 4, 5, 6, 7, 8, 9

$counter -> (1000); #reset the counter
foreach (1..3) {
  print &$counter, "\n";
}
print "\n"; # displays 1000, 1001, 1002

Closures also provide a way to define objects so that their properties cannot be accessed from anywhere other than the object's own methods. The trick is to define the object's underlying data in terms of an anonymous subroutine that has access to an otherwise inaccessible hash, in the same way that the variable $count is hidden here. We will take a look at doing this in Chapter 19, along with tied objects, which would allow us to disguise a counter like the one above as a read-only scalar variable that increments each time we access it.

Handling Context: an Example - Page 22
Professional Perl Programming
Assignable Subroutines - Page 24


Up to => Home / Authoring / Languages / Perl / ProPerl




Jupiter Online Media: internet.comearthweb.comDevx.commediabistro.comGraphics.com

Search:

Jupitermedia Corporation has two divisions: Jupiterimages and Jupiter Online Media

Jupitermedia Corporate Info


Legal Notices, Licensing, & Permissions, Privacy Policy.

Web Hosting | Newsletters | Tech Jobs | Shopping | E-mail Offers