Exegesis 4
Control Structures
by Damian ConwayApril 02, 2002
Editor's note: this document is out of date and remains here for historic interest. See Synopsis 4 for the current design information.
In Apocalypse 4, Larry explains the fundamental changes to
flow and block control in Perl 6. The changes bring fully integrated
exceptions; a powerful new switch statement; a coherent mechanism
for polymorphic matching; a greatly enhanced for loop;
and unification of blocks, subroutines and closures.
Let's dive right in.
"Now, Witness the Power of This Fully Operational Control Structure"
We'll consider a simple interactive RPN calculator. The real thing would have many more operators and values, but that's not important right now.
class Err::BadData is Exception {...}
module Calc;
my class NoData is Exception {
method warn(*@args) { die @args }
}
my %var;
my sub get_data ($data) {
given $data {
when /^\d+$/ { return %var{""} = $_ }
when 'previous' { return %var{""} // fail NoData }
when %var { return %var{""} = %var{$_} }
default { die Err::BadData : msg=>"Don't understand $_" }
}
}
sub calc (str $expr, int $i) {
our %operator is private //= (
'*' => { $^a * $^b },
'/' => { $^a / $^b },
'~' => { ($^a + $^b) / 2 },
);
my @stack;
my $toknum = 1;
for split /\s+/, $expr -> $token {
try {
when %operator {
my @args = splice @stack, -2;
push @stack, %operator{$token}(*@args)
}
when '.', ';', '=' {
last
}
use fatal;
push @stack, get_data($token);
CATCH {
when Err::Reportable { warn $!; continue }
when Err::BadData { $!.fail(at=>$toknum) }
when NoData { push @stack, 0 }
when /division by zero/ { push @stack, Inf }
}
}
NEXT { $toknum++ }
}
fail Err::BadData: msg=>"Too many operands" if @stack > 1;
return %var{'$' _ $i} = pop(@stack) but true;
}
module main;
for 1..Inf -> $i {
print "$i> ";
my $expr = <> err last;
print "$i> $( Calc::calc(i=>$i, expr=>$expr) )\n";
}
An Exceptionally Promising Beginning
The calculator is going to handle internal and external errors using Perl 6's OO exception mechanism. This means that we're going to need some classes for those OO exceptions to belong to.
To create those classes, the class keyword is used. For example:
class Err::BadData is Exception {...}
|
Related Articles
Apocalypse 4 |
After this declaration, Err::BadData is a class name (or rather,
by analogy to "filehandle," it's a "classname"). Either way, it can
then be used as a type specifier wherever Perl 6 expects one. Unlike
Perl 5, that classname is not a bareword string: It's a genuine
first-class symbol in the program. In object-oriented terms, we
could think of a classname as a meta-object -- an object that describes
the attributes and behavior of other objects.
Modules and packages are also first class in Perl 6, so we can also refer to their names directly, or take references to them, or look them up in the appropriate symbol table.
Classes can take properties, just like variables and values. Generally, those properties will specify variations in the behavior of the class. For example:
class B::Like::Me is interface;
specifies that the B::Like::Me class defines a (Java-like) interface that any subclass must implement.
The is Exception is not, however, a standard property. Indeed,
Exception is the name of another (standard, built-in) class.
When a classname like this is used as if it were a property,
the property it confers is inheritance. Specifically, Err::BadData
is defined as inheriting from the Exception base class.
In Perl 5, that would have been:
# Perl 5 code
package Err::BadData;
use base 'Exception';
So now class Err::BadData will have all the exceptionally useful
properties of the Exception class.
Having classnames as "first class" symbols of the program means that it's also important to be able to pre-declare them (to avoid compile-time "no such class or module" errors). So we need a new syntax for declaring the existence of classes/modules/packages, without actually defining their behavior.
To do that we write:
class MyClass {...}
That right. That's real, executable, Perl 6 code.
We're defining the class, but using the new Perl 6 "yada-yada-yada" operator in a block immediately after the classname. By using the "I'm-eventually-going-to-put-something-here-but-not-just-yet" marker, we indicate that this definition is only a stub or placeholder. In this way, we introduce the classname into the current scope without needing to provide the complete description of the class.
By the way, this is also the way we can declare other types of symbols in Perl 6 without actually defining them:
module Alpha {...}
package Beta {...}
method Gamma::delta(Gamma $self: $d1, $d2) {...}
sub epsilon() {...}
In our example, the Err::BadData classname is introduced in precisely that way:
class Err::BadData is Exception {...}
which means that we can refer to the class by name, even though it has not yet been completely defined.
In fact, in this example, Err::BadData is never completely
defined. So we'd get a fatal compile-time error: "Missing
definition for class Err::BadData." Then we'd realize we
either forgot to eventually define the class, or that we had
really meant to write:
class Err::BadData is Exception {} # Define new exception class with
# no methods or attributes
# except those it inherits
# See below.

