Author: wayland
Date: 2009-02-24 00:33:42 +0100 (Tue, 24 Feb 2009)
New Revision: 25503
Added:
docs/Perl6/Spec/S14-roles-and-parametric-types.pod
Modified:
docs/Perl6/Spec/S12-objects.pod
docs/Perl6/Spec/S29-functions.pod
Log:
S29: s/Container.pod/Containers.pod/
S14/S12: Extracted S14 from S12, added Jonathan's blog entry, a bit from S02,
and a bit
from the spectests
Modified: docs/Perl6/Spec/S12-objects.pod
===================================================================
--- docs/Perl6/Spec/S12-objects.pod 2009-02-23 21:06:52 UTC (rev 25502)
+++ docs/Perl6/Spec/S12-objects.pod 2009-02-23 23:33:42 UTC (rev 25503)
@@ -1105,378 +1105,6 @@
A C<proto> declaration may not occur after a C<multi> declaration in the
same scope.
-=head1 Roles
-
-Classes are primarily in charge of object management, and only
-secondarily in charge of software reuse. In PerlĀ 6, roles take over
-the job of managing software reuse. Depending on how you care to look
-at it, a role is like a partial class, or an interface with default
-implementation, or a set of generic methods and their associated data,
-or a class closed at compile time.
-
-Roles may be composed into a class at compile time, in which case
-you get automatic detection of conflicting methods. A role may also
-be mixed into a class or object at run time to produce an anonymous
-derived class with extra capabilities, but in this case conflicting
-methods are overridden by the new role silently. In either case,
-a class is necessary for instantiation--a role may not be directly
-instantiated.
-
-A role is declared like a class, but with a C<role> keyword:
-
- role Pet {
- method feed ($food) {
- $food.open_can;
- $food.put_in_bowl;
- self.eat($food);
- }
- }
-
-A role may not inherit from a class, but may be composed of other
-roles. However, this "crony" composition is not evaluated until
-class composition time. This means that if two roles bring in the
-same crony, there's no conflict--it's just as if the class pulled in
-the crony role itself and the respective roles didn't. A role may
-never conflict with itself regardless of its method of incorporation.
-A role that brings in two conflicting crony roles I<may> resolve them
-as if it were a class. This solution is accepted by the class unless
-the class supplies its own solution. If two different roles resolve
-the same crony conflict two different ways, those roles are themselves
-in conflict and must be resolved by a "more derived" role or the class.
-
-A role doesn't know its own type until it is composed into a class.
-Any mention of its main type (such as C<::?CLASS>) is generic, as is
-any reference to C<self> or the type of the invocant. You can use
-a role name as a type, but only for constraints, not for declaring
-actual objects. (However, if you use a role as if it were a class,
-an anonymous class is generated that composes the role, which provides
-a way to force a role to test its crony composition for infelicities.)
-
-A role's main type is generic by default, but you can also parameterize
-other types explicitly using type parameters:
-
- role Pet[::Petfood = TableScraps] {
- method feed (Petfood $food) {...}
- }
-
-(Note that in this case you must not use ::Petfood in the inner declaration,
-or it would rebind the type to type of the actual food parameter.)
-
-If a role merely declares methods without defining them, it degenerates
-to an interface:
-
- role Pet {
- method feed ($food) {...}
- method groom () {...}
- method scratch (:$where) {...}
- }
-
-Note that, while these methods must become available at class
-composition time, they might be supplied by any of: another role,
-the class itself, or some superclass. We know the methods that are
-coming from the other roles or the class, but we don't necessarily know
-the complete set of methods supplied by our super classes if they are
-open or rely on wildcard delegation. However, the class composer is
-allowed to assume that only currently declared superclass methods or
-non-wildcard methods are going to be available. A stub can always
-be installed somewhere to "supply" a missing method's declaration.
-
-Roles may have attributes:
-
- role Pet {
- has $.collar = Collar.new(Tag.new);
- method id () { return $.collar.tag }
- method lose_collar () { undefine $.collar }
- }
-
-If you want to parameterize the initial value of a role attribute,
-be sure to put a double semicolon if you don't want the parameter to
-be considered part of the long name:
-
- role Pet[::ID;; $tag] {
- has ID $.collar .= new($tag);
- }
-
-Within a role the C<has> declarator always indicates the declaration
-from the viewpoint of the class. Therefore a private attribute declared
-using C<has> is private to the class, not to the role. You may wish to
declare an attribute
-that is hidden even from the class; a completely private role
-attribute may be declared like this:
-
- my $!spleen;
-
-The name of such a private attribute is always considered lexically scoped.
-If a role declares private lexical items, those items are private to
-the role due to the nature of lexical scoping. Accessors to such
-items may be exported to the class, but this is not the default.
-In particular, a role may say
-
- trusts ::?Class;
-
-to allow C<self!attr()> access to the role's C<$!attr> variables with the
-class or from other roles composed into the class. Conflicts between
-private accessors are also caught at composition time, but of course
-need not consider super classes, since no-one outside the current
-class (or a trusted class) can call a private accessor at all.
-(Private accessors are never virtual, and must be package qualified
-if called from a trusted scope other than our own. That is, it's
-either C<self!attr()> or C<$obj!TrustsMe::attr().>)
-
-A role may also distinguish a shared method
-
- has method foo ...
- method foo ... # same
-
-from a nonshared private method:
-
- my method !foo ...
- my method foo ... # same, but &foo is aliased to &!foo
-
-Generally you'd just use a lexically scoped sub, though.
-
- my sub foo ...
-
-[Conjectural: To put a private sub into the class, say
-
- our sub !foo ...
-
-]
-
-A role can abstract the decision to delegate:
-
- role Pet {
- has $groomer handles <bathe groom trim> = hire_groomer();
- }
-
-Note that this puts the three methods into the class as well as
-C<$groomer>. In contrast, "C<my $!groomer>" would only put the
-three methods; the attribute itself is private to the role.
-
-A role is allowed to declare an additional inheritance for its class when
-that is considered an implementation detail:
-
- role Pet {
- is Friend;
- }
-
-A class incorporates a role with the verb "does", like this:
-
- class Dog is Mammal does Pet does Sentry {...}
-
-or equivalently, within the body of the class closure:
-
- class Dog {
- is Mammal;
- does Pet;
- does Sentry;
- ...
- }
-
-There is no ordering dependency among the roles.
-
-A class's explicit method definition hides any role definition of
-the same name. A role method in turn hides any methods inherited
-from other classes.
-
-If there are no method name conflicts between roles (or with the
-class), then each role's methods can be installed in the class. If,
-however, two roles try to introduce a method of the same name the
-composition of the class fails. (Two C<has> attributes of the same
-name, whether public or private, are simply merged into one slot,
-provided the types are the same; otherwise, the composition fails.
-Role-private attributes are not merged, and from the viewpoint of
-the composition, don't even exist, except to allocate a slot for each
-such attribute.)
-
-There are several ways to solve method conflicts. The first is simply to
-write a class method that overrides the conflicting role methods, perhaps
-figuring out which role method to call.
-
-Alternately, if the role's methods are declared C<multi>, they can be
-disambiguated based on their long name. If the roles forget to declare
-them as multi, you can force a multi on the roles' methods by installing
-a proto stub in the class being constructed:
-
- proto method shake {...}
-
-(This declaration need not precede the C<does> clause textually, since
-roles are not actually composed until the end of the class definition,
-at which point we know which roles are to be composed together
-in a single logical operation, as well as how the class intends to
-override the roles.)
-
-The proto method will be called if the multi fails:
-
- proto method shake { warn "They couldn't decide" }
-
-Run-time mixins are done with C<does> and C<but>. The C<does> binary
-operator is a mutator that derives a new anonymous class (if necessary)
-and binds the object to it:
-
- $fido does Sentry
-
-The C<does> infix operator is non-associative, so this is a syntax error:
-
- $fido does Sentry does Tricks does TailChasing does Scratch;
-
-You can, however, say
-
- $fido does Sentry;
- $fido does Tricks;
- $fido does TailChasing;
- $fido does Scratch;
-
-And since it returns the left side, you can also say:
-
- ((($fido does Sentry) does Tricks) does TailChasing) does Scratch;
-
-Unlike the compile-time role composition, each of these layers on a new
-mixin with a new level of inheritance, creating a new anonymous class
-for dear old Fido, so that a C<.chase> method from C<TailChasing> hides a
-C<.chase> method from C<Sentry>.
-
-You can also mixin a precomposed set of roles:
-
- $fido does (Sentry, Tricks, TailChasing, Scratch);
-
-This will level the playing field for collisions among the new
-set of roles, and guarantees the creation of no more than one more
-anonymous class. Such a role still can't conflict with itself, but it
-can hide its previous methods in the parent class, and the calculation
-of what conflicts is done again for the set of roles being mixed in.
-If you can't do compile-time composition, we strongly recommend this
-approach for run-time mixins since it approximates a compile-time
-composition at least for the new roles involved.
-
-A role applied with C<does> may be parameterized with an initializer
-in parentheses, but only if the role supplies exactly one attribute
-to the mixin class:
-
- $fido does Wag($tail);
- $line does taint($istainted);
-
-The supplied initializer will be coerced to type of the attribute.
-Note that this initializer is in addition to any parametric type
-supplied in square brackets, which is considered part of the actual
-type name:
-
- $myobj does Array[:of(Int)](@initial)
-
-The C<but> operator creates a copy and works on that. It also knows
-how to generalize a particular enumerated value to its role. So
-
- 0 but True
-
-is short for something like:
-
- 0 but Bool::True
-
-A property is defined by a role like this:
-
- role SomeRole {
- has SomeType $.prop is rw = 1;
- }
-
-You can declare a property with
-
- my int property answer;
-
-and that declares a role whose name is the same as the accessor:
-
- my role answer {
- has int $.answer is rw;
- }
-
-Then you can say
-
- $a = 0 but answer(42)
-
-Note that the parenthesized form is I<not> a subroutine or method call.
-It's just special initializing syntax for roles that contain a single
-property. The above really means something like:
-
- $a = ($anonymous = 0) does answer(42);
-
-which really means:
-
- (($anonymous = 0) does answer).answer = 42;
- $a = $anonymous;
-
-Which is why there's a C<but> operator.
-
-=head1 Traits
-
-Traits are just properties (roles) applied to declared items like
-containers or classes. It's the declaration of the item itself that
-makes traits seem more permanent than ordinary properties. In addition
-to adding the property, a trait can also have side effects.
-
-Traits are generally applied with the "is" keyword, though not always.
-To define a trait handler for an "is xxx" trait, define one or
-more multisubs into a property role like this:
-
- role xxx {
- has Int $.xxx;
- multi trait_auxiliary:is(xxx $trait, Class $container; $arg?) {...}
- multi trait_auxiliary:is(xxx $trait, Any $container; $arg?) {...}
- }
-
-Then it can function as a trait. A well-behaved trait handler will say
-
- $container does xxx($arg);
-
-somewhere inside to set the metadata on the container correctly.
-Since a class can function as a role when it comes to parameter type
-matching, you can also say:
-
- class MyBase {
- multi trait_auxiliary:is(MyBase $base, Class $class; $arg?) {...}
- multi trait_auxiliary:is(MyBase $tied, Any $container; $arg?) {...}
- }
-
-These capture control if C<MyBase> wants to capture control of how it gets
-used by any class or container. But usually you can just let it call
-the generic defaults:
-
- multi trait_auxiliary:is(Class $base, Class $class; $arg?) {...}
-
-which adds C<$base> to the "isa" list of C<$class>, or
-
- multi trait_auxiliary:is(Class $tied, Any $container; $arg?) {...}
-
-which sets the "tie" type of the container to the implementation type
-in C<$tied>.
-
-Most traits are introduced by use of a "helping verb", which could
-be something like "C<is>", or "C<will>", or "C<can>", or "C<might>",
-or "C<should>", or "C<does>". We call these helping verbs "trait
-auxiliaries". Here's "C<will>", which (being syntactic sugar) merely
-delegates to back to "is":
-
- multi sub trait_auxiliary:will($trait, $container; &arg) {
- trait_auxiliary:is($trait, $container, &arg);
- }
-
-Other traits are applied with a single word, and we call one of those a
-"trait verb". For instance, the "C<as>" trait
-is defined something like this:
-
- role as {
- has ReturnType $.as;
- multi sub trait_verb:as($container; ReturnType $arg) {
- $container does as($arg);
- }
- ...
- }
-
-Unlike compile-time roles, which all flatten out in the same class,
-compile-time traits are applied one at a time, like mixin roles.
-You can, in fact, apply a trait to a container at run time, but
-if you do, it's just an ordinary mixin role. You have to call the
-appropriate C<trait_auxiliary:is()> routine yourself if you want it to
-do any extra shenanigans. The compiler won't call it for you at run
-time like it would at compile time.
-
=head1 Delegation
Delegation lets you pretend that some other object's methods are your own.
Added: docs/Perl6/Spec/S14-roles-and-parametric-types.pod
===================================================================
--- docs/Perl6/Spec/S14-roles-and-parametric-types.pod
(rev 0)
+++ docs/Perl6/Spec/S14-roles-and-parametric-types.pod 2009-02-23 23:33:42 UTC
(rev 25503)
@@ -0,0 +1,490 @@
+=encoding utf8
+
+=head1 TITLE
+
+Synopsis 12: Roles and Parametric Types
+
+=head1 AUTHOR
+
+Larry Wall <[email protected]>
+
+=head1 VERSION
+
+ Maintainer: Larry Wall <[email protected]>
+ Date: 24 Feb 2009, extracted from S12-objects.pod
+ Last Modified: 24 Feb 2009
+ Number: 14
+ Version: 1
+
+=head1 Overview
+
+This synopsis summarizes Apocalypse 14, which discusses roles and parametric
types.
+
+=head1 Roles
+
+Classes are primarily in charge of object management, and only
+secondarily in charge of software reuse. In PerlĀ 6, roles take over
+the job of managing software reuse. Depending on how you care to look
+at it, a role is like a partial class, or an interface with default
+implementation, or a set of generic methods and their associated data,
+or a class closed at compile time.
+
+Roles may be composed into a class at compile time, in which case
+you get automatic detection of conflicting methods. A role may also
+be mixed into a class or object at run time to produce an anonymous
+derived class with extra capabilities, but in this case conflicting
+methods are overridden by the new role silently. In either case,
+a class is necessary for instantiation--a role may not be directly
+instantiated.
+
+A role is declared like a class, but with a C<role> keyword:
+
+ role Pet {
+ method feed ($food) {
+ $food.open_can;
+ $food.put_in_bowl;
+ self.eat($food);
+ }
+ }
+
+A role may not inherit from a class, but may be composed of other
+roles. However, this "crony" composition is not evaluated until
+class composition time. This means that if two roles bring in the
+same crony, there's no conflict--it's just as if the class pulled in
+the crony role itself and the respective roles didn't. A role may
+never conflict with itself regardless of its method of incorporation.
+A role that brings in two conflicting crony roles I<may> resolve them
+as if it were a class. This solution is accepted by the class unless
+the class supplies its own solution. If two different roles resolve
+the same crony conflict two different ways, those roles are themselves
+in conflict and must be resolved by a "more derived" role or the class.
+
+A role doesn't know its own type until it is composed into a class.
+Any mention of its main type (such as C<::?CLASS>) is generic, as is
+any reference to C<self> or the type of the invocant. You can use
+a role name as a type, but only for constraints, not for declaring
+actual objects. (However, if you use a role as if it were a class,
+an anonymous class is generated that composes the role, which provides
+a way to force a role to test its crony composition for infelicities.)
+
+A role's main type is generic by default, but you can also parameterize
+other types explicitly using type parameters:
+
+ role Pet[::Petfood = TableScraps] {
+ method feed (Petfood $food) {...}
+ }
+
+(Note that in this case you must not use ::Petfood in the inner declaration,
+or it would rebind the type to type of the actual food parameter.)
+
+If a role merely declares methods without defining them, it degenerates
+to an interface:
+
+ role Pet {
+ method feed ($food) {...}
+ method groom () {...}
+ method scratch (:$where) {...}
+ }
+
+Note that, while these methods must become available at class
+composition time, they might be supplied by any of: another role,
+the class itself, or some superclass. We know the methods that are
+coming from the other roles or the class, but we don't necessarily know
+the complete set of methods supplied by our super classes if they are
+open or rely on wildcard delegation. However, the class composer is
+allowed to assume that only currently declared superclass methods or
+non-wildcard methods are going to be available. A stub can always
+be installed somewhere to "supply" a missing method's declaration.
+
+Roles may have attributes:
+
+ role Pet {
+ has $.collar = Collar.new(Tag.new);
+ method id () { return $.collar.tag }
+ method lose_collar () { undefine $.collar }
+ }
+
+If you want to parameterize the initial value of a role attribute,
+be sure to put a double semicolon if you don't want the parameter to
+be considered part of the long name:
+
+ role Pet[::ID;; $tag] {
+ has ID $.collar .= new($tag);
+ }
+
+Within a role the C<has> declarator always indicates the declaration
+from the viewpoint of the class. Therefore a private attribute declared
+using C<has> is private to the class, not to the role. You may wish to
declare an attribute
+that is hidden even from the class; a completely private role
+attribute may be declared like this:
+
+ my $!spleen;
+
+The name of such a private attribute is always considered lexically scoped.
+If a role declares private lexical items, those items are private to
+the role due to the nature of lexical scoping. Accessors to such
+items may be exported to the class, but this is not the default.
+In particular, a role may say
+
+ trusts ::?Class;
+
+to allow C<self!attr()> access to the role's C<$!attr> variables with the
+class or from other roles composed into the class. Conflicts between
+private accessors are also caught at composition time, but of course
+need not consider super classes, since no-one outside the current
+class (or a trusted class) can call a private accessor at all.
+(Private accessors are never virtual, and must be package qualified
+if called from a trusted scope other than our own. That is, it's
+either C<self!attr()> or C<$obj!TrustsMe::attr().>)
+
+A role may also distinguish a shared method
+
+ has method foo ...
+ method foo ... # same
+
+from a nonshared private method:
+
+ my method !foo ...
+ my method foo ... # same, but &foo is aliased to &!foo
+
+Generally you'd just use a lexically scoped sub, though.
+
+ my sub foo ...
+
+[Conjectural: To put a private sub into the class, say
+
+ our sub !foo ...
+
+]
+
+A role can abstract the decision to delegate:
+
+ role Pet {
+ has $groomer handles <bathe groom trim> = hire_groomer();
+ }
+
+Note that this puts the three methods into the class as well as
+C<$groomer>. In contrast, "C<my $!groomer>" would only put the
+three methods; the attribute itself is private to the role.
+
+A role is allowed to declare an additional inheritance for its class when
+that is considered an implementation detail:
+
+ role Pet {
+ is Friend;
+ }
+
+A class incorporates a role with the verb "does", like this:
+
+ class Dog is Mammal does Pet does Sentry {...}
+
+or equivalently, within the body of the class closure:
+
+ class Dog {
+ is Mammal;
+ does Pet;
+ does Sentry;
+ ...
+ }
+
+There is no ordering dependency among the roles.
+
+A class's explicit method definition hides any role definition of
+the same name. A role method in turn hides any methods inherited
+from other classes.
+
+If there are no method name conflicts between roles (or with the
+class), then each role's methods can be installed in the class. If,
+however, two roles try to introduce a method of the same name the
+composition of the class fails. (Two C<has> attributes of the same
+name, whether public or private, are simply merged into one slot,
+provided the types are the same; otherwise, the composition fails.
+Role-private attributes are not merged, and from the viewpoint of
+the composition, don't even exist, except to allocate a slot for each
+such attribute.)
+
+There are several ways to solve method conflicts. The first is simply to
+write a class method that overrides the conflicting role methods, perhaps
+figuring out which role method to call.
+
+Alternately, if the role's methods are declared C<multi>, they can be
+disambiguated based on their long name. If the roles forget to declare
+them as multi, you can force a multi on the roles' methods by installing
+a proto stub in the class being constructed:
+
+ proto method shake {...}
+
+(This declaration need not precede the C<does> clause textually, since
+roles are not actually composed until the end of the class definition,
+at which point we know which roles are to be composed together
+in a single logical operation, as well as how the class intends to
+override the roles.)
+
+The proto method will be called if the multi fails:
+
+ proto method shake { warn "They couldn't decide" }
+
+Run-time mixins are done with C<does> and C<but>. The C<does> binary
+operator is a mutator that derives a new anonymous class (if necessary)
+and binds the object to it:
+
+ $fido does Sentry
+
+The C<does> infix operator is non-associative, so this is a syntax error:
+
+ $fido does Sentry does Tricks does TailChasing does Scratch;
+
+You can, however, say
+
+ $fido does Sentry;
+ $fido does Tricks;
+ $fido does TailChasing;
+ $fido does Scratch;
+
+And since it returns the left side, you can also say:
+
+ ((($fido does Sentry) does Tricks) does TailChasing) does Scratch;
+
+Unlike the compile-time role composition, each of these layers on a new
+mixin with a new level of inheritance, creating a new anonymous class
+for dear old Fido, so that a C<.chase> method from C<TailChasing> hides a
+C<.chase> method from C<Sentry>.
+
+You can also mixin a precomposed set of roles:
+
+ $fido does (Sentry, Tricks, TailChasing, Scratch);
+
+This will level the playing field for collisions among the new
+set of roles, and guarantees the creation of no more than one more
+anonymous class. Such a role still can't conflict with itself, but it
+can hide its previous methods in the parent class, and the calculation
+of what conflicts is done again for the set of roles being mixed in.
+If you can't do compile-time composition, we strongly recommend this
+approach for run-time mixins since it approximates a compile-time
+composition at least for the new roles involved.
+
+A role applied with C<does> may be parameterized with an initializer
+in parentheses, but only if the role supplies exactly one attribute
+to the mixin class:
+
+ $fido does Wag($tail);
+ $line does taint($istainted);
+
+The supplied initializer will be coerced to type of the attribute.
+Note that this initializer is in addition to any parametric type
+supplied in square brackets, which is considered part of the actual
+type name:
+
+ $myobj does Array[:of(Int)](@initial)
+
+The C<but> operator creates a copy and works on that. It also knows
+how to generalize a particular enumerated value to its role. So
+
+ 0 but True
+
+is short for something like:
+
+ 0 but Bool::True
+
+A property is defined by a role like this:
+
+ role SomeRole {
+ has SomeType $.prop is rw = 1;
+ }
+
+You can declare a property with
+
+ my int property answer;
+
+and that declares a role whose name is the same as the accessor:
+
+ my role answer {
+ has int $.answer is rw;
+ }
+
+Then you can say
+
+ $a = 0 but answer(42)
+
+Note that the parenthesized form is I<not> a subroutine or method call.
+It's just special initializing syntax for roles that contain a single
+property. The above really means something like:
+
+ $a = ($anonymous = 0) does answer(42);
+
+which really means:
+
+ (($anonymous = 0) does answer).answer = 42;
+ $a = $anonymous;
+
+Which is why there's a C<but> operator.
+
+=head1 Traits
+
+Traits are just properties (roles) applied to declared items like
+containers or classes. It's the declaration of the item itself that
+makes traits seem more permanent than ordinary properties. In addition
+to adding the property, a trait can also have side effects.
+
+Traits are generally applied with the "is" keyword, though not always.
+To define a trait handler for an "is xxx" trait, define one or
+more multisubs into a property role like this:
+
+ role xxx {
+ has Int $.xxx;
+ multi trait_auxiliary:is(xxx $trait, Class $container; $arg?) {...}
+ multi trait_auxiliary:is(xxx $trait, Any $container; $arg?) {...}
+ }
+
+Then it can function as a trait. A well-behaved trait handler will say
+
+ $container does xxx($arg);
+
+somewhere inside to set the metadata on the container correctly.
+Since a class can function as a role when it comes to parameter type
+matching, you can also say:
+
+ class MyBase {
+ multi trait_auxiliary:is(MyBase $base, Class $class; $arg?) {...}
+ multi trait_auxiliary:is(MyBase $tied, Any $container; $arg?) {...}
+ }
+
+These capture control if C<MyBase> wants to capture control of how it gets
+used by any class or container. But usually you can just let it call
+the generic defaults:
+
+ multi trait_auxiliary:is(Class $base, Class $class; $arg?) {...}
+
+which adds C<$base> to the "isa" list of C<$class>, or
+
+ multi trait_auxiliary:is(Class $tied, Any $container; $arg?) {...}
+
+which sets the "tie" type of the container to the implementation type
+in C<$tied>.
+
+Most traits are introduced by use of a "helping verb", which could
+be something like "C<is>", or "C<will>", or "C<can>", or "C<might>",
+or "C<should>", or "C<does>". We call these helping verbs "trait
+auxiliaries". Here's "C<will>", which (being syntactic sugar) merely
+delegates to back to "is":
+
+ multi sub trait_auxiliary:will($trait, $container; &arg) {
+ trait_auxiliary:is($trait, $container, &arg);
+ }
+
+Other traits are applied with a single word, and we call one of those a
+"trait verb". For instance, the "C<as>" trait
+is defined something like this:
+
+ role as {
+ has ReturnType $.as;
+ multi sub trait_verb:as($container; ReturnType $arg) {
+ $container does as($arg);
+ }
+ ...
+ }
+
+Unlike compile-time roles, which all flatten out in the same class,
+compile-time traits are applied one at a time, like mixin roles.
+You can, in fact, apply a trait to a container at run time, but
+if you do, it's just an ordinary mixin role. You have to call the
+appropriate C<trait_auxiliary:is()> routine yourself if you want it to
+do any extra shenanigans. The compiler won't call it for you at run
+time like it would at compile time.
+
+=head1 Parametric Types
+
+Types can take parameters. Parametric types are named using square brackets,
so:
+
+ my Hash of Array of Recipe %book;
+
+actually means:
+
+ my Hash[of => Array[of => Recipe]] %book;
+
+=head2 Parametric Roles
+
+In Perl 6, roles can also take parameters. Roles exist to enable greater
re-use of code
+than we could get through having plain old classes, and by allowing them to be
+parameterized we open the door to even more re-use. Taking a simple example,
imagine we
+wanted to factor out a "greet" method into a role, which takes somebody's name
and greets
+them. We want to parameterize it on the greeting.
+
+role Greet[Str $greeting] {
+ method greet() { say "$greeting!"; }
+}
+class EnglishMan does Greet["Hello"] { }
+class Slovak does Greet["Ahoj"] { }
+class Lolcat does Greet["OH HAI"] { }
+EnglishMan.new.greet(); # Hello
+Slovak.new.greet(); # Ahoj
+Lolcat.new.greet(); # OH HAI
+
+Similarly, we could do a role for requests.
+
+role Request[Str $statement] {
+ method request($object) { say "$statement $object?"; }
+}
+class EnglishMan does Request["Please can I have a"] { }
+class Slovak does Request["Prosim si"] { }
+class Lolcat does Request["I CAN HAZ"] { }
+EnglishMan.new.request("yorkshire pudding");
+Slovak.new.request("borovicka");
+Lolcat.new.request("CHEEZEBURGER");
+
+Sadly, the Slovak output sucks here. Borovicka is the nominative form of the
word, and we
+need to decline it into the accusative case. But some languages don't care
about that, and
+we don't want to have to make them all supply a transform. Thankfully, you can
write many
+roles with the same short name, and a different signature, and multi-dispatch
will pick
+the right one for you. So we write something to produce the accusative case in
Slovak and
+pass it in. Here's the new code.
+
+role Request[Str $statement] {
+ method request($object) { say "$statement $object?"; }
+}
+role Request[Str $statement, &transform] {
+ method request($object) {
+ say "$statement " ~ transform($object) ~ "?";
+ }
+}
+module Language::Slovak {
+ sub accusative($nom) {
+ # ...and before some smartass points it out, I know
+ # I'm missing some of the masculine animate declension...
+ return $nom.subst(/a$/, 'u');
+ }
+}
+class EnglishMan does Request["Please can I have a"] { }
+class Slovak does Request["Prosim si", &Language::Slovak::accusative] { }
+class Lolcat does Request["I CAN HAZ"] { }
+EnglishMan.new.request("yorkshire pudding");
+Slovak.new.request("borovicka");
+Lolcat.new.request("CHEEZEBURGER");
+
+Which means we can now properly order our borovicka in Slovakia, which is
awesome. Until
+you do it in a loop and find the Headache['very bad'] role got mixed into
yourself
+overnight, anyway...
+
+Role attributes can also be used to initialise attributes:
+
+ role AttrParams[$a, $b] {
+ has $.x = $a;
+ has $.y = $b;
+ }
+
+...and to constrain types.
+
+ role TypeParams[::T] {
+ method x(T $x) { return "got a " ~ T ~ " it was $x" }
+ }
+
+ class IntShower does TypeParams[Int] { } # Shows Ints
+ class StrShower does TypeParams[Str] { } # Shows Strs
+
+ print IntShower.new.x(42); # Prints 'got a Int it was 42'
+ print StrShower.new.x("OH HAI"); # Prints 'got a Str it was OH HAI'
+ print IntShower.new.x("OH HAI"); # Dies
+
+
+
+=for vim:set expandtab sw=4:
Modified: docs/Perl6/Spec/S29-functions.pod
===================================================================
--- docs/Perl6/Spec/S29-functions.pod 2009-02-23 21:06:52 UTC (rev 25502)
+++ docs/Perl6/Spec/S29-functions.pod 2009-02-23 23:33:42 UTC (rev 25503)
@@ -684,67 +684,67 @@
=over
-=item all -- see S32-setting-library/Container.pod
+=item all -- see S32-setting-library/Containers.pod
-=item any -- see S32-setting-library/Container.pod
+=item any -- see S32-setting-library/Containers.pod
-=item cat -- see S32-setting-library/Container.pod
+=item cat -- see S32-setting-library/Containers.pod
-=item classify -- see S32-setting-library/Container.pod
+=item classify -- see S32-setting-library/Containers.pod
=item defined -- see S32-setting-library/Scalars.pod
-=item grep -- see S32-setting-library/Container.pod
+=item grep -- see S32-setting-library/Containers.pod
-=item first -- see S32-setting-library/Container.pod
+=item first -- see S32-setting-library/Containers.pod
-=item keys -- see S32-setting-library/Container.pod
+=item keys -- see S32-setting-library/Containers.pod
-=item kv -- see S32-setting-library/Container.pod
+=item kv -- see S32-setting-library/Containers.pod
-=item join -- see S32-setting-library/Container.pod
+=item join -- see S32-setting-library/Containers.pod
-=item map -- see S32-setting-library/Container.pod
+=item map -- see S32-setting-library/Containers.pod
-=item max -- see S32-setting-library/Container.pod
+=item max -- see S32-setting-library/Containers.pod
-=item min -- see S32-setting-library/Container.pod
+=item min -- see S32-setting-library/Containers.pod
-=item none -- see S32-setting-library/Container.pod
+=item none -- see S32-setting-library/Containers.pod
-=item one -- see S32-setting-library/Container.pod
+=item one -- see S32-setting-library/Containers.pod
-=item pairs -- see S32-setting-library/Container.pod
+=item pairs -- see S32-setting-library/Containers.pod
=item print -- see S32-setting-library/IO.pod
=item printf -- see S32-setting-library/IO.pod
-=item roundrobin -- see S32-setting-library/Container.pod
+=item roundrobin -- see S32-setting-library/Containers.pod
-=item pick -- see S32-setting-library/Container.pod
+=item pick -- see S32-setting-library/Containers.pod
-=item reduce -- see S32-setting-library/Container.pod
+=item reduce -- see S32-setting-library/Containers.pod
-=item reverse -- see S32-setting-library/Container.pod
+=item reverse -- see S32-setting-library/Containers.pod
=item say -- see S32-setting-library/IO.pod
-=item shape -- see S32-setting-library/Container.pod
+=item shape -- see S32-setting-library/Containers.pod
-=item sort -- see S32-setting-library/Container.pod
+=item sort -- see S32-setting-library/Containers.pod
-=item srand -- see S32-setting-library/Container.pod
+=item srand -- see S32-setting-library/Numeric.pod
=item undefine -- see S32-setting-library/Scalar.pod
=item uri -- see S32-setting-library/IO.pod
-=item values -- see S32-setting-library/Container.pod
+=item values -- see S32-setting-library/Containers.pod
=item warn -- see S32-setting-library/Any.pod
-=item zip -- see S32-setting-library/Container.pod
+=item zip -- see S32-setting-library/Containers.pod
=back