On Topic
Topic and Topicalisers in Perl 6
by Allison RandalOctober 30, 2002
A few concepts in Perl 6 are strange at first sight. They seem hard to understand, but it's only because they're new and different. They aren't deep mystical concepts known only to Tibetan lamas. Anyone can understand them, but it helps to start with a common-sense explanation.
This article looks at the concepts of "topic" and "topicalizer". The words aren't quotes from a particularly nasty bit of Vogon poetry. They're actually common terms from the field of linguistics ... which some might say is even worse. Still, the best way to understand topic in Perl is to understand its source.
Topic in Linguistics
Every larger unit of human language has a topic -- whether it's a sentence, a paragraph, a conversation or some other sizable chunk. The topic is the central idea of the unit. It's the focus of what's communicated. Native speakers usually have no trouble figuring out what the current topic is, when they think about it. If two little old ladies were talking over a cup of tea:
"I saw Lister yesterday."
"Really? What's he up to these days?"
"Oh, you know, drunk again, and mooning over that awful Krissy Kochanski."
etc ...
and someone asked an observer what the conversation was about, they would instantly reply "Lister".
Topicalizers in Linguistics
A topicalizer is simply a word that marks some thing or some idea as the current topic. In English, we have topicalizers such as "for", "given" and "regarding":
"For our first trick tonight, ladies and gentlemen, my partner Kryten will attempt to eat a boiled egg."
"Given that God is infinite, and that the universe is also infinite, would you like a toasted tea-cake?"
"Regarding topicalizers, I should point out that this sentence starts with one."
Topic in Perl
Now we need to adapt the linguistic definition of topic to Perl. In Perl, the topic is the most important variable in a block of code. It can be any variable: a scalar, array, hash, object. To be more accurate, it's the underlying storage location that's the topic. This might sound a little too abstract, but it's an important distinction. Variables are really only names we use to get at stored values. A single storage location can have multiple names. In English, "Rimmer", "he" and "the hologram" could all appear in a text meaning the same person. In Perl $_, $name, %characters{'title'} and any number of other variables could appear in a section of code as different ways of accessing a single value. And if that value is the current topic then all the variables connected to it are too. This will be important later.
At this point, the average reader is thinking "That's very interesting, but why do I care what the topic is? I've gotten along just fine without it all these years. Why start now?"
And the answer is: it's not required. No one has to understand topic to use it, any more than they have to understand gravity to catch a ball.
Why? It's a really simple rule. We'll call it the first law of topics:
Topic is $_. Any time a value becomes the current topic, $_ becomes
another one of the names for that value. We say $_ is aliased to it. So,
all it takes to use topic is to use $_ either explicitly or implicitly
in all the old familiar places, like chomp, print and
substitutions, and in a few new places, like when statements and with
unary dot.
Even so, it's still a good idea to understand topic. Understanding gravity makes a number of things that seem unrelated suddenly fit. Things like apples falling, planes crashing, the way the moon and sun move, baseball, and rollercoasters. It's the same with topic. Any programmer can use $_ without understanding topic. But when they understand topic, it becomes a logical system instead of a random collection of "things $_ does". I like logical systems.
Topicalizers in Perl
A topicalizer in Perl is a keyword or construct that makes a value
become the current topic. The current topicalizers are given, for,
method, rule, ->, certain bare closures, and CATCH
blocks, but the cast of characters keeps growing.
Coal and Switches
Perl 6's switch, the given construct, is the prime example of a
topicalizer. Its sole purpose is to make the value passed to it the
current topic within the block.
given $name {
when "Lister" { print "I'm a curryaholic." }
when "Cat" { print "Orange?! With this suit?!" }
when "Rimmer" { print "4,691 irradiated haggis." }
}
So, in this example, the given makes $name the current topic by
aliasing it to $_. Then the when statements compare against $_. After
the block, $_ regains the value in the outer scope. In Perl 6, $_ is
just an ordinary lexical variable and every topicalizer creates its own
$_ variable, lexically scoped to its associated block.
Fruit Loops and M&M's
The for loop is the classic topicalizer. It was topicalizing long
before most of us had a word for the activity. for is similar to
given, but instead of creating a single topic, it creates a series of
topics, one for each iteration.
for @orders {
when /scone/ {
print "Would you like some toast?";
}
when /croissant/ {
print "Hot, buttered, scrummy toast?";
}
when /toast/ {
print "Really? How about a muffin?";
}
}
Just like given, for takes a value, in this case the current
element of the array, and makes it the topic.
In simple cases like these, both for and given create the $_ alias
read-write. This is the same as Perl 5: any change to $_ inside the
block modifies the original value.
Bow and Arrow
The new and improved arrow (->) is the most flexible topicalizer.
It appears in a variety of different contexts. By itself ->
creates an anonymous subroutine just like sub.
-> $param { ... }
# is the same as:
sub ($param) { ... }
The only differences are that -> doesn't require parentheses
around its parameter list, and that -> topicalizes its first
parameter.
In the following example, the first expression creates an anonymous sub
and stores it in $cleanup. When the sub stored in $cleanup executes,
the $line parameter takes the string argument and becomes the current
topic, so both $line and $_ are aliased to the value of $intro. The
usual suspects, chomp, substitution and print then use the topic
as default.
$cleanup = -> $line is rw {
s:w/Captain Rimmer!/the bloke/;
$line _= " who cleans the soup machine!";
print;
}
$intro = "Fear not, I'm Captain Rimmer!";
$cleanup($intro);
Unlike the simple for and given, the arrow creates its aliases
read-only by default. The is rw property marks both the named alias
and the $_ alias as read-write. Without the property attached, any
statements within the block that modify $line or $_ cause a compile-time
error just as if they had been explicitly flagged is constant.
The arrow isn't limited to working alone. It can also combine with other topicalizers. When it does, it creates a named alias for the current topic.
for @lines -> $line is rw {
s:w/Captain Rimmer!/the bloke/;
$line _= " who cleans the soup machine!";
print;
}
As the for iterates over the array it aliases every element in turn
to $line and to $_. This takes the place of the Perl 5 way of aliasing a
loop variable:
# Perl 5
for my $line (@lines) {
$line =~ s/Captain Rimmer!/the bloke/;
$line .= " who cleans the soup machine!";
print $line;
}
The Perl 6 way has some added benefits, though. Since the arrow aliases
both $line and $_ to the current value, it works with the defaulting
constructs, like print, but also provides a more meaningful name than
$_ when an explicitly named variable is necessary.
The first example of for and the example of the anonymous sub
reference are fascinatingly similar. The only difference is one is
stored in a variable to be called later and one is tacked onto a for.
Really, all the for example has done is replace the loop's block with
an anonymous sub reference. This is the second advantage of the Perl 6
way. Because $line is now the parameter of a subroutine, it's
automatically lexically scoped to the block. The my happens
implicitly.
The arrow also combines with constructs that aren't topicalizers, like
if and while, and allows them to topicalize.
if %people{$name}{'details'}{'age'} -> $age {
print "$age already?\n";
if $age > 3000000 {
print "How was your stasis?\n";
} elsif $age < 10 {
print "How 'bout a muffin?\n";
}
}
As the if tests the truth value of the element of the data structure,
the arrow also aliases that value to $age and to $_. The example could
have accessed the hash of hashes of hashes directly each time it needed
the age value, but the short alias is much more convenient.
This feature is really only useful with simple truth tests. The truth
value tested in the following example isn't 3 or $counter, it's the
result of a complex conditional, $counter > 3.
if $counter > 3 -> $value {
# do something with $value
}
The result will be true or false, but if it's false, the block will never execute. In fact, when the truth test is false, $value is never aliased at all. It simply doesn't exist. A lexically scoped variable with a true value would have the same effect.
if $counter > 3 {
my $value = 1;
# do something with $value
}
So the arrow isn't a Ronco plum-pitter, yoghurt-squirter, do-everything
tool. When it's useful, it's very, very useful, but when it's not...
well... don't use it. :)
Pages: 1, 2 |





