[Chicago-talk] perl objects/references/modules

Steven Lembark lembark at wrkhors.com
Tue Dec 16 16:34:02 CST 2003



-- "Dooley, Michael" <Dooley.Michael at con-way.com>

> is it me or does anyone else find callbacks/closures frustrating to
> understand?

I was lukcy: I'd seen jump tables in C long before so the basic
idea of leaving code at a location for the sake of running it
later on seemed natural to me.

>
> I mean like anything after anon subroutines (chap 6 in perl
> objects/references/modules) is pretty confusing.

Anon sub's are like any other kind of referent: think of
them as fodder for dereferencing.

	my $a = \@array;

	...

	$a->[ $offset ]


or

	my $b = \%hash;

	...

	$b->{ $key }

or

	my $c = \&subname;

	...

	$c->( $arg1, $arg2 );

for anon-sub closures just know that the sub has some
built-in values that were made available when it was
created:

	sub prefix
	{
		my $prefix = shift;

		# caller gets back a sub that prefixes its
		# arguments with whatever the contents of
		# $prefix were when the sub was created --
		# make multiple call to the prefix sub and
		# you can get back multiple-prefixors.
		#
		# java calls things like this prefix sub
		# "factories".

		sub { join '', $prefix, @_ }
	}

	...

	my $fixer = prefix "foo_";

	...

	print $fixer->( 'bar' ), "\n";  # call returns "foo_bar";

	print $fixer->( 'bar', 'bletch' ); # returns foo_barbletch


Another example is something that increments its original
argument from whatever value it had to begin with:

	sub increment
	{
		my $i = shift || 0;

		sub { ++$i }
	}

	my $lo = increment 10;
	my $hi = increment 100;

	print $lo->(); # 11
	print $hi->(); # 101
	print $lo->(); # 12
	print $lo->(); # 13

these can be handy to keep track of various events: just
hand back a counter of some sort with whatever you wanto
to count and call it when the events happen. You can
interrogate the counters when you're done by calling them
one last time. In this rather contrived case, a counter is
used to incremnt a counter at each value in a hash:

	sub counter
	{
		my $value = shift || 0;
		
		# returns the current count, helpful for
		# checking on the way out.

		sub { $value++ }
	}

	# store a list of known names, look for them in the
	# input records, upping the counter each time.


	for my $name ( @names )
	{
		$hash{$names} = counter 0;
	}

	for my $word ( @input_data )
	{
		$hash{$word}->() if $hash{$word};
	}

	# now display the counts

	for my $name ( sort keys %hash )
	{
		print "$name: " . $hash{$name}->()
	}


While this is obviously an idiotic way to count names. But
you could be doing quite a bit more than just counting
the names. In fact, if you could even have passed the
hash off to another subroutine that had no idea what was
being done with the names. You could even be doing
completely different things with the different names and
the subroutine doing the work wouldn't have to care: just
by calling what's in $hash{$name} the job just gets done.

The abiliy to write one piece of code that says "I don't care
what you do with the values, just tell me where to go with
them" is the point of closures: the code actually calling
the closure doesn't have to know at all what the closure itself
does, just that it's there.




--
Steven Lembark                               2930 W. Palmer
Workhorse Computing                       Chicago, IL 60647
                                            +1 888 359 3508



More information about the Chicago-talk mailing list