Apocalypse 12
by Larry Wall
|
Pages: 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20
Editor's Note: this Apocalypse is out of date and remains here for historic reasons. See Synopsis 12 for the latest information.
The official, unofficial slogan of Perl 6 is "Second System Syndrome Done Right!". After you read this Apocalypse you will at least be certain that we got the "Second System" part down pat. But we've also put in a little bit of work on the "Done Right" part, which we hope you'll recognize. The management of complexity is complex, but only if you think about it. The goal of Perl 6 is to discourage you from thinking about it unnecessarily.
Speaking of thinking unnecessarily, please don't think that everything we write here is absolutely true. We expect some things to change as people point out various difficulties. That's the way all the other Apocalypses have worked, so why should this one be different?
When I say "we", I don't just mean "me". I mean everyone who has participated in the design, including the Perl 6 cabal, er, design team, the readers (and writers) of the perl6-language mailing list, and all the participants who wrote or commented on the original RFCs. For this Apocalypse we've directly considered the following RFCs:
RFC PSA Title
=== === =====
032 abb A Method of Allowing Foreign Objects in Perl
067 abb Deep Copying, a.k.a., Cloning Around
092 abb Extensible Meta-Object Protocol
095 acc Object Classes
101 bcc Apache-Like Event and Dispatch Handlers
126 aaa Ensuring Perl's Object-Oriented Future
137 bdd Overview: Perl OO Should <Not> Be Fundamentally Changed
147 rr Split Scalars and Objects/References into Two Types
152 bdd Replace Invocant in @_ with self() builtin
163 bdd Objects: Autoaccessors for Object Data Structures
171 rr My Dog $spot Should Call a Constructor Implicitly
174 bdd Improved Parsing and Flexibility of Indirect Object Syntax
187 abb Objects : Mandatory and Enhanced Second Argument to C<bless>
188 acc Objects : Private Keys and Methods
189 abb Objects : Hierarchical Calls to Initializers and Destructors
190 acc Objects : NEXT Pseudoclass for Method Redispatch
193 acc Objects : Core Support for Method Delegation
223 bdd Objects: C<use invocant> Pragma
224 bdd Objects : Rationalizing C<ref>, C<attribute::reftype>, and
C<builtin:blessed>
244 cdr Method Calls Should Not Suffer from the Action on a Distance
254 abb Class Collections: Provide the Ability to Overload Classes
256 abb Objects : Native Support for Multimethods
265 abc Interface Polymorphism Considered Lovely
277 bbb Method Calls Should Suffer from Ambiguity by Default
307 rr PRAYER: What Gets Said When You C<bless> Something
335 acc Class Methods Introspection: What Methods Does this Object
Support?
336 bbb Use Strict 'objects': A New Pragma for Using Java-Like
Objects in Perl
These RFCs contain many interesting ideas, and many more "cries for help". Usually in these Apocalypses, I discuss the design with respect to each of the RFCs. However, in this case I won't, because most of these RFCs fail in exactly the same way--they assume the Perl 6 object model to be a set of extensions to the Perl 5 object model. But as it turns out, that would have been a great way to end up with Second System Syndrome Done Wrong. Perl 5's OO system is a great workbench, but it has some issues that have to be dealt with systematically rather than piecemeal.
Some of the Problems with Perl 5 OO
A little too orthogonal
It has often been claimed that Perl 5 OO was "bolted on", but that's inaccurate. It was "bolted through", at right angles to all other reference types, such that any reference could be blessed into being an object. That's way cool, but it's often a little too cool.
Not quite orthogonal enough
It's too hard to treat built-in types as objects when you want to. Perl
5's tie interface helps, but is suboptimal in several ways,
not the least of which is that it only works on variables, not values.
Forced non-encapsulation
Because of the ability to turn (almost) anything into an object, a derived class had to be aware of the internal data type of its base class. Even after convention settled on hashes as the appropriate default data structure, one had to be careful not to stomp on the attributes of one's base class.
A little too minimal
Some people will be surprised to hear it, but Perl is a minimalist language
at heart. It's just minimalistic about weird things compared to your
average language. Just as the binding of parameters to @_
was a minimalistic approach, so too the entire Perl 5 object system
was an attempt to see how far you could drive a few features. But many
of the following difficulties stem from that.
Too much keyword reuse
In Perl 5, a class is just a package, a method is just a subroutine, and an object is just a blessed referent. That's all well and good, and it is still fundamentally true in Perl 6. However, Perl 5 made the mistake of reusing the same keywords to express similar ideas. That's not how natural languages work--we often use different words to express similar ideas, the better to make subtle distinctions.
Too difficult to capture metadata
Because Perl 5 reused keywords and treated parameter binding as something you do via a list assignment at runtime, it was next to impossible for the compiler to tell which subroutines were methods and which ones were really just subroutines. Because hashes are mutable, it was difficult to tell at compile time what the attribute names were going to be.
Inside-out interfaces
The Perl 5 solution to the previous problem was to declare more things
at compile time. Unfortunately, since the main way to do things at compile
time was to invoke use, all the compile-time interfaces
were shoehorned into use's syntax, which, powerful though
it may be, is often completely inside-out from a reasonable interface.
For instance, overloading is done by passing a list of pairs to use,
when it would be much more natural to simply declare appropriate methods
with appropriate names and traits. The base and fields
pragmas are also kludges.
Not enough convention
Because of the flexibility of the Perl 5 approach, there was never any "obvious" way to do it. So best practices had to be developed by each group, and of course, everyone came up with a slightly different solution. Now, we're not going to be like some folks and confuse "obvious" with "the only way to do it". This is still Perl, after all, and the flexibility will still be there if you need it. But by convention, there needs to be a standard look to objects and classes so that they can interoperate. There's more than one way to do it, but one of those is the standard way.
Wrong conventions
The use of arrow where most of the rest of the world uses dot was confusing.
Everything possible, but difficult
The upshot of the previous problems was that, while Perl 5 made it easy to use objects and classes, it was difficult to try to define classes or derive from them.
Perl 5 Non-Problems
While there are plenty of problems with Perl 5's OO system, there are some things it did right.
Generating class by running code at compile time
One of the big advances in Perl 5 was that a program could be in charge
of its own compilation via use statements and BEGIN
blocks. A Perl program isn't a passive thing that a compiler has its
way with, willy-nilly. It's an active thing that negotiates with the
compiler for a set of semantics. In Perl 6 we're not shying away from
that, but taking it further, and at the same time hiding it in a more
declarative style. So you need to be aware that, although many of the
things we'll be talking about here look like declarations,
they trigger Perl code that runs during compilation. Of such methods
are metaclasses made. (While these methods are often triggered by grammar
rule reductions, remember from Apocalypse 5 that all these grammar rules
are also running under the user's control. You can tweak the language
without the crude ax of source filtering.)
There are many roads to polymorphism
In looking for an "obvious" way to conventionalize Perl's object system, we shouldn't overlook the fact that there's more than one obvious way, and different approaches work better in different circumstances. Inheritance is one way (and typically the most overused), but we also need good support for composition, delegation, and parametric types. Cutting across those techniques are issues of interface, implementation, and mixtures of interface and implementation. There are multiple strategies for ambiguity resolution as well, and no single strategy is always right. (Unless the boss says so.)
People using a class shouldn't have to think hard
In making it easier to define and derive classes, we must be careful not to make it harder to use classes.
Trust in Convention, But Keep Your Powder Dry
So to summarize this summary, what we're proposing to develop is a set of conventions for how object orientation ought to work in Perl 6--by default. But there should also be enough hooks to customize things to your heart's content, hopefully without undue impact on the sensibilities of others.
And in particular, there's enough flexibility in the new approach that,
if you want to, you can still program in a way much like the old Perl
5 approach. There's still a bless method, and you can still
pretend that an object is a hash--though it isn't anymore.
However, as with all the rest of the design of Perl 6, the overriding concern has been that the language scale well. That means Perl has to scale down as well as up. Perl has to work well both as a first language and as a last language. We believe our design fulfills this goal--though, of course, only time will tell.
One other note: if you haven't read the previous Apocalypses and Exegeses, a lot of this is going to be complete gobbledygook to you. (Of course, even if you have read them, this might still be gobbledygook. You take your chances in life...)
An Easy Example
Before we start talking about all the hard things that should be possible, let's look at an example of some of the easy things that should be easy. Suppose we define a Point object that (for some strange reason) allows you to adjust the y-axis but not the x-axis.
class Point {
has $.x;
has $.y is rw;
method clear () { $.x = 0; $.y = 0; }
}
my $point = Point.new(x => 2, y => 3);
$a = $point.y; # okay
$point.y = 42; # okay
$b = $point.x; # okay
$point.x = -1; # illegal, default is read-only
$point.clear; # reset to 0,0
If you compare that to how it would have to be written in Perl 5, you'll note a number of differences:
- It uses the keywords
classandmethodrather thanpackageandsub. - The attributes are named in explicit declarations rather than implicit hash keys.
- It is impossible to confuse the attribute variables with ordinary variables because of the extra dot (which also associates the attributes visually with method calls).
- Perhaps most importantly, we did not have to commit to using a hash (or any other external data structure) for the object's values.
- We didn't have to write a constructor.
- The implicit constructor automatically knows how to map named arguments to the attribute names.
- We didn't have to write the accessor methods.
- The accessors are by default read-only outside the class, and you can't get at the attributes from outside the class without an accessor. (Inside the class you can use the attributes directly.)
- The invocant of the
clearmethod is implicit. - And perhaps most obviously, Perl 6 uses
.instead of->to dereference an object.
Now suppose we want to derive from Point, and add a z-axis. That's just:
class Point3d is Point {
has $:z = 123;
method clear () { $:z = 0; next; }
}
my $point3d = Point3d.new(x => 2, y => 3, z => 4);
$c = $point3d.z; # illegal, $:z is invisible
The implicit constructor automatically sorts out the named arguments
to the correct initializers for you. If you omit the z value, it will
default to 123. And the new clear method calls the old
clear method merely by invoking next, without the dodgy
"super" semantics that break down under MI. We also declared the $:z
attribute to be completely private by using a colon instead of a dot.
No accessor for it is visible outside the class. (And yes, OO purists,
our other attributes should probably have been private in the first
place...that's why we're making it just as easy to write a private attribute
as a public one.)
If any of that makes your head spin, I'm sure the following will clear
it right up. :-)
Pages: 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20 |

