Author: larry Date: Sat Dec 23 12:50:23 2006 New Revision: 13501 Modified: doc/trunk/design/syn/S02.pod doc/trunk/design/syn/S06.pod
Log: Housekeeping move of basic types section from S06 to S02, no other changes. Modified: doc/trunk/design/syn/S02.pod ============================================================================== --- doc/trunk/design/syn/S02.pod (original) +++ doc/trunk/design/syn/S02.pod Sat Dec 23 12:50:23 2006 @@ -12,9 +12,9 @@ Maintainer: Larry Wall <[EMAIL PROTECTED]> Date: 10 Aug 2004 - Last Modified: 16 Dec 2006 + Last Modified: 23 Dec 2006 Number: 2 - Version: 81 + Version: 82 This document summarizes Apocalypse 2, which covers small-scale lexical items and typological issues. (These Synopses also contain @@ -656,6 +656,344 @@ =back +=head2 Native types + +Values with these types autobox to their uppercase counterparts when +you treat them as objects: + + bit single native bit + int native signed integer + uint native unsigned integer (autoboxes to Int) + buf native buffer (finite seq of native ints or uints, no Unicode) + num native floating point + complex native complex number + bool native boolean + +=head2 Undefined types + +These can behave as values or objects of any class, except that +C<defined> always returns false. One can create them with the +built-in C<undef> and C<fail> functions. (See S02 for how failures +are handled.) + + Undef Undefined (can serve as a prototype object of any class) + Whatever Wildcard (like undef, but subject to do-what-I-mean via MMD) + Failure Failure (throws an exception if not handled properly) + +=head2 Immutable types + +Objects with these types behave like values, i.e. C<$x === $y> is true +if and only if their types and contents are identical (that is, if +C<$x.WHICH> eqv C<$y.WHICH>). + + Bit Perl single bit (allows traits, aliasing, undef, etc.) + Int Perl integer (allows Inf/NaN, arbitrary precision, etc.) + Str Perl string (finite sequence of Unicode characters) + Num Perl number + Complex Perl complex number + Bool Perl boolean + Exception Perl exception + Code Base class for all executable objects + Block Executable objects that have lexical scopes + List Lazy Perl list (composed of Seq and Range parts) + Seq Completely evaluated (hence immutable) sequence + Range A pair of Ordered endpoints; gens lazy Seq in list context + Set Unordered Seq that allows no duplicates (does KeyHash, but ro) + Bag Unordered Seq that allows duplicates (does KeyHash, but ro) + Junction Sets with additional behaviours + Pair Seq of two elements that serves as a one-element Mapping + Mapping Pairs with no duplicate keys + Signature Function parameters (left-hand side of a binding) + Capture Function call arguments (right-hand side of a binding) + Blob An undifferentiated mass of bits + +=head2 Mutable types + +Objects with these types have distinct C<.WHICH> values that do not change +even if the object's contents change. + + Scalar Perl scalar + Array Perl array + Hash Perl hash + KeyHash Perl hash that autodeletes values matching default + KeySet KeyHash of Bool (does Set in list/array context) + KeyBag KeyHash of UInt (does Bag in list/array context) + Buf Perl buffer (a stringish array of memory locations) + IO Perl filehandle + Routine Base class for all wrappable executable objects + Sub Perl subroutine + Method Perl method + Submethod Perl subroutine acting like a method + Macro Perl compile-time subroutine + Regex Perl pattern + Match Perl match, usually produced by applying a pattern + Package Perl 5 compatible namespace + Module Perl 6 standard namespace + Class Perl 6 standard class namespace + Role Perl 6 standard generic interface/implementation + Object Perl 6 object + Grammar Perl 6 pattern matching namespace + +A C<KeyHash> differs from a normal C<Hash> in how it handles default +values. If the value of a C<KeyHash> element is set to the default +value for the C<KeyHash>, the element is deleted. If undeclared, +the default default for a C<KeyHash> is 0 for numeric types, C<False> +for boolean types, and the null string for string and buffer types. +A C<KeyHash> of a C<Object> type defaults to the undefined prototype +for that type. More generally, the default default is whatever defined +value an C<undef> would convert to for that value type. A C<KeyHash> +of C<Scalar> deletes elements that go to either 0 or the null string. +A C<KeyHash> also autodeletes keys for normal undef values (that is, +those undefined values that do not contain an unthrown exception). + +A C<KeySet> is a C<KeyHash> of booleans with a default of C<False>. +If you use the C<Hash> interface and increment an element of a +C<KeySet> its value becomes true (creating the element if it doesn't +exist already). If you decrement the element it becomes false and +is automatically deleted. When not used as a C<Hash> (that is, +when used as an C<Array> or list or C<Set> object) a C<KeySet> +behaves as a C<Set> of its keys. (Since the only possible value of +a C<KeySet> is the C<True> value, it need not be represented in +the actual implementation with any bits at all.) + +A C<KeyBag> is a C<KeyHash> of C<UInt> with default of 0. If you +use the C<Hash> interface and increment an element of a C<KeyBag> +its value is increased by one (creating the element if it doesn't exist +already). If you decrement the element the value is decreased by one; +if the value goes to 0 the element is automatically deleted. When not +used as a C<Hash> (that is, when used as an C<Array> or list or C<Bag> +object) a C<KeyBag> behaves as a C<Bag> of its keys, with each key +replicated the number of times specified by its corresponding value. +(Use C<.kv> or C<.pairs> to suppress this behavior in list context.) + +=head2 Value types + +Explicit types are optional. Perl variables have two associated types: +their "value type" and their "implementation type". (More generally, any +container has an implementation type, including subroutines and modules.) +The value type is stored as its C<of> property, while the implementation +type of the container is just the object type of the container itself. + +The value type specifies what kinds of values may be stored in the +variable. A value type is given as a prefix or with the C<of> keyword: + + my Dog $spot; + my $spot of Dog; + +In either case this sets the C<of> property of the container to C<Dog>. + +Subroutines have a variant of the C<of> property, C<returns>, that sets +the C<returns> property instead. The C<returns> property specifies a +constraint (or perhaps coercion) to be enforced on the return value (either +by explicit call to C<return> or by implicit fall-off-the-end return). +This constraint, unlike the C<of> property, is not advertised as the +type of the routine. You can think of it as the implicit type signature of +the (possibly implicit) return statement. It's therefore available for +type inferencing within the routine but not outside it. If no inner type +is declared, it is assumed to be the same as the C<of> type, if declared. + + sub get_pet() of Animal {...} # of type, obviously + our Animal sub get_pet() {...} # of type + sub get_pet() returns Animal {...} # inner type + +A value type on an array or hash specifies the type stored by each element: + + my Dog @pound; # each element of the array stores a Dog + + my Rat %ship; # the value of each entry stores a Rat + +The key type of a hash may be specified as a shape trait--see S09. + +=head2 Implementation types + +The implementation type specifies how the variable itself is implemented. It is +given as a trait of the variable: + + my $spot is Scalar; # this is the default + my $spot is PersistentScalar; + my $spot is DataBase; + +Defining an implementation type is the Perl 6 equivalent to tying +a variable in Perl 5. But Perl 6 variables are tied directly at +declaration time, and for performance reasons may not be tied with a +run-time C<tie> statement unless the variable is explicitly declared +with an implementation type that does the C<Tieable> role. + +However, package variables are always considered C<Tieable> by default. +As a consequence, all named packages are also C<Tieable> by default. +Classes and modules may be viewed as differently tied packages. +Looking at it from the other direction, classes and modules that +wish to be bound to a global package name must be able to do the +C<Package> role. + +=head2 Hierarchical types + +A non-scalar type may be qualified, in order to specify what type of +value each of its elements stores: + + my Egg $cup; # the value is an Egg + my Egg @carton; # each elem is an Egg + my Array of Egg @box; # each elem is an array of Eggs + my Array of Array of Egg @crate; # each elem is an array of arrays of Eggs + my Hash of Array of Recipe %book; # each value is a hash of arrays of Recipes + +Each successive C<of> makes the type on its right a parameter of the +type on its left. Parametric types are named using square brackets, so: + + my Hash of Array of Recipe %book; + +actually means: + + my Hash[of => Array[of => Recipe]] %book; + +Because the actual variable can be hard to find when complex types are +specified, there is a postfix form as well: + + my Hash of Array of Recipe %book; # HoHoAoRecipe + my %book of Hash of Array of Recipe; # same thing + +The C<returns> form may be used in subroutines: + + my sub get_book ($key) returns Hash of Array of Recipe {...} + +Alternately, the return type may be specified within the signature: + + my sub get_book ($key --> Hash of Array of Recipe) {...} + +There is a slight difference, insofar as the type inferencer will +ignore a C<returns> but pay attention to C<< --> >> or prefix type +declarations, also known as the C<of> type. Only the inside of the +subroutine pays attention to C<returns>. + +You may also specify the C<of> type as the C<of> trait: + + my Hash of Array of Recipe sub get_book ($key) {...} + my sub get_book ($key) of Hash of Array of Recipe {...} + +=head2 Polymorphic types + +Anywhere you can use a single type you can use a set of types, for convenience +specifiable as if it were an "or" junction: + + my Int|Str $error = $val; # can assign if $val~~Int or $val~~Str + +Fancier type constraints may be expressed through a subtype: + + subset Shinola of Any where {.does(DessertWax) and .does(FloorTopping)}; + if $shimmer ~~ Shinola {...} # $shimmer must do both interfaces + +Since the terms in a parameter could be viewed as a set of +constraints that are implicitly "anded" together (the variable itself +supplies type constraints, and C<where> clauses or tree matching just +add more constraints), we relax this to allow juxtaposition of +types to act like an "and" junction: + + # Anything assigned to the variable $mitsy must conform + # to the type Fish and either the Cat or Dog type... + my Cat|Dog Fish $mitsy = new Fish but { int rand 2 ?? .does Cat + !! .does Dog }; + +=head2 Parameter types + +Parameters may be given types, just like any other variable: + + sub max (int @array is rw) {...} + sub max (@array of int is rw) {...} + +=head2 Generic types + +Within a declaration, a class variable (either by itself or +following an existing type name) declares a new type name and takes +its parametric value from the actual type of the parameter it is +associated with. It declares the new type name in the same scope +as the associated declaration. + + sub max (Num ::X @array) { + push @array, X.new(); + } + +The new type name is introduced immediately, so two such types in +the same signature must unify compatibly if they have the same name: + + sub compare (Any ::T $x, T $y) { + return $x eqv $y; + } + +=head2 Return types + +On a scoped subroutine, a return type can be specified before or after +the name. We call all return types "return types", but distinguish +two kinds of return types, the C<inner> type and the C<of> type, +because the C<of> type is normally an "official" named type and +declares the official interface to the routine, while the C<inner> +type is merely a constraint on what may be returned by the routine +from the routine's point of view. + + our sub lay returns Egg {...} # inner type + our Egg sub lay {...} # of type + our sub lay of Egg {...} # of type + our sub lay (--> Egg) {...} # of type + + my sub hat returns Rabbit {...} # inner type + my Rabbit sub hat {...} # of type + my sub hat of Rabbit {...} # of type + my sub hat (--> Rabbit) {...} # of type + +If a subroutine is not explicitly scoped, it belongs to the current +namespace (module, class, grammar, or package), as if it's scoped with +the C<our> scope modifier. Any return type must go after the name: + + sub lay returns Egg {...} # inner type + sub lay of Egg {...} # of type + sub lay (--> Egg) {...} # of type + +On an anonymous subroutine, any return type can only go after the C<sub> +keyword: + + $lay = sub returns Egg {...}; # inner type + $lay = sub of Egg {...}; # of type + $lay = sub (--> Egg) {...}; # of type + +but you can use a scope modifier to introduce an C<of> prefix type: + + $lay = my Egg sub {...}; # of type + $hat = my Rabbit sub {...}; # of type + +Because they are anonymous, you can change the C<my> modifier to C<our> +without affecting the meaning. + +The return type may also be specified after a C<< --> >> token within +the signature. This doesn't mean exactly the same thing as C<returns>. +The C<of> type is the "official" return type, and may therefore be +used to do type inferencing outside the sub. The C<inner> type only +makes the return type available to the internals of the sub so that +the C<return> statement can know its context, but outside the sub we +don't know anything about the return value, as if no return type had +been declared. The prefix form specifies the C<of> type rather than +the C<inner> type, so the return type of + + my Fish sub wanda ($x) { ... } + +is known to return an object of type Fish, as if you'd said: + + my sub wanda ($x --> Fish) { ... } + +I<not> as if you'd said + + my sub wanda ($x) returns Fish { ... } + +It is possible for the C<of> type to disagree with the C<inner> type: + + my Squid sub wanda ($x) returns Fish { ... } + +or equivalently, + + my sub wanda ($x --> Squid) returns Fish { ... } + +This is not lying to yourself--it's lying to the world. Having a +different inner type is useful if you wish to hold your routine to +a stricter standard than you let on to the outside world, for instance. + =head1 Names and Variables =over 4 Modified: doc/trunk/design/syn/S06.pod ============================================================================== --- doc/trunk/design/syn/S06.pod (original) +++ doc/trunk/design/syn/S06.pod Sat Dec 23 12:50:23 2006 @@ -13,9 +13,9 @@ Maintainer: Larry Wall <[EMAIL PROTECTED]> Date: 21 Mar 2003 - Last Modified: 18 Dec 2006 + Last Modified: 23 Dec 2006 Number: 6 - Version: 65 + Version: 66 This document summarizes Apocalypse 6, which covers subroutines and the @@ -1336,348 +1336,6 @@ Also, it is illegal to use placeholder variables in a block that already has a signature, because the autogenerated signature would conflict with that. -=head1 Built-in Types - -=head2 Native types - -[This stuff belongs in S02.] - -Values with these types autobox to their uppercase counterparts when -you treat them as objects: - - bit single native bit - int native signed integer - uint native unsigned integer (autoboxes to Int) - buf native buffer (finite seq of native ints or uints, no Unicode) - num native floating point - complex native complex number - bool native boolean - -=head2 Undefined types - -These can behave as values or objects of any class, except that -C<defined> always returns false. One can create them with the -built-in C<undef> and C<fail> functions. (See S02 for how failures -are handled.) - - Undef Undefined (can serve as a prototype object of any class) - Whatever Wildcard (like undef, but subject to do-what-I-mean via MMD) - Failure Failure (throws an exception if not handled properly) - -=head2 Immutable types - -Objects with these types behave like values, i.e. C<$x === $y> is true -if and only if their types and contents are identical (that is, if -C<$x.WHICH> eqv C<$y.WHICH>). - - Bit Perl single bit (allows traits, aliasing, undef, etc.) - Int Perl integer (allows Inf/NaN, arbitrary precision, etc.) - Str Perl string (finite sequence of Unicode characters) - Num Perl number - Complex Perl complex number - Bool Perl boolean - Exception Perl exception - Code Base class for all executable objects - Block Executable objects that have lexical scopes - List Lazy Perl list (composed of Seq and Range parts) - Seq Completely evaluated (hence immutable) sequence - Range A pair of Ordered endpoints; gens lazy Seq in list context - Set Unordered Seq that allows no duplicates (does KeyHash, but ro) - Bag Unordered Seq that allows duplicates (does KeyHash, but ro) - Junction Sets with additional behaviours - Pair Seq of two elements that serves as a one-element Mapping - Mapping Pairs with no duplicate keys - Signature Function parameters (left-hand side of a binding) - Capture Function call arguments (right-hand side of a binding) - Blob An undifferentiated mass of bits - -=head2 Mutable types - -Objects with these types have distinct C<.WHICH> values that do not change -even if the object's contents change. - - Scalar Perl scalar - Array Perl array - Hash Perl hash - KeyHash Perl hash that autodeletes values matching default - KeySet KeyHash of Bool (does Set in list/array context) - KeyBag KeyHash of UInt (does Bag in list/array context) - Buf Perl buffer (a stringish array of memory locations) - IO Perl filehandle - Routine Base class for all wrappable executable objects - Sub Perl subroutine - Method Perl method - Submethod Perl subroutine acting like a method - Macro Perl compile-time subroutine - Regex Perl pattern - Match Perl match, usually produced by applying a pattern - Package Perl 5 compatible namespace - Module Perl 6 standard namespace - Class Perl 6 standard class namespace - Role Perl 6 standard generic interface/implementation - Object Perl 6 object - Grammar Perl 6 pattern matching namespace - -A C<KeyHash> differs from a normal C<Hash> in how it handles default -values. If the value of a C<KeyHash> element is set to the default -value for the C<KeyHash>, the element is deleted. If undeclared, -the default default for a C<KeyHash> is 0 for numeric types, C<False> -for boolean types, and the null string for string and buffer types. -A C<KeyHash> of a C<Object> type defaults to the undefined prototype -for that type. More generally, the default default is whatever defined -value an C<undef> would convert to for that value type. A C<KeyHash> -of C<Scalar> deletes elements that go to either 0 or the null string. -A C<KeyHash> also autodeletes keys for normal undef values (that is, -those undefined values that do not contain an unthrown exception). - -A C<KeySet> is a C<KeyHash> of booleans with a default of C<False>. -If you use the C<Hash> interface and increment an element of a -C<KeySet> its value becomes true (creating the element if it doesn't -exist already). If you decrement the element it becomes false and -is automatically deleted. When not used as a C<Hash> (that is, -when used as an C<Array> or list or C<Set> object) a C<KeySet> -behaves as a C<Set> of its keys. (Since the only possible value of -a C<KeySet> is the C<True> value, it need not be represented in -the actual implementation with any bits at all.) - -A C<KeyBag> is a C<KeyHash> of C<UInt> with default of 0. If you -use the C<Hash> interface and increment an element of a C<KeyBag> -its value is increased by one (creating the element if it doesn't exist -already). If you decrement the element the value is decreased by one; -if the value goes to 0 the element is automatically deleted. When not -used as a C<Hash> (that is, when used as an C<Array> or list or C<Bag> -object) a C<KeyBag> behaves as a C<Bag> of its keys, with each key -replicated the number of times specified by its corresponding value. -(Use C<.kv> or C<.pairs> to suppress this behavior in list context.) - -=head2 Value types - -Explicit types are optional. Perl variables have two associated types: -their "value type" and their "implementation type". (More generally, any -container has an implementation type, including subroutines and modules.) -The value type is stored as its C<of> property, while the implementation -type of the container is just the object type of the container itself. - -The value type specifies what kinds of values may be stored in the -variable. A value type is given as a prefix or with the C<of> keyword: - - my Dog $spot; - my $spot of Dog; - -In either case this sets the C<of> property of the container to C<Dog>. - -Subroutines have a variant of the C<of> property, C<returns>, that sets -the C<returns> property instead. The C<returns> property specifies a -constraint (or perhaps coercion) to be enforced on the return value (either -by explicit call to C<return> or by implicit fall-off-the-end return). -This constraint, unlike the C<of> property, is not advertised as the -type of the routine. You can think of it as the implicit type signature of -the (possibly implicit) return statement. It's therefore available for -type inferencing within the routine but not outside it. If no inner type -is declared, it is assumed to be the same as the C<of> type, if declared. - - sub get_pet() of Animal {...} # of type, obviously - our Animal sub get_pet() {...} # of type - sub get_pet() returns Animal {...} # inner type - -A value type on an array or hash specifies the type stored by each element: - - my Dog @pound; # each element of the array stores a Dog - - my Rat %ship; # the value of each entry stores a Rat - -The key type of a hash may be specified as a shape trait--see S09. - -=head2 Implementation types - -The implementation type specifies how the variable itself is implemented. It is -given as a trait of the variable: - - my $spot is Scalar; # this is the default - my $spot is PersistentScalar; - my $spot is DataBase; - -Defining an implementation type is the Perl 6 equivalent to tying -a variable in Perl 5. But Perl 6 variables are tied directly at -declaration time, and for performance reasons may not be tied with a -run-time C<tie> statement unless the variable is explicitly declared -with an implementation type that does the C<Tieable> role. - -However, package variables are always considered C<Tieable> by default. -As a consequence, all named packages are also C<Tieable> by default. -Classes and modules may be viewed as differently tied packages. -Looking at it from the other direction, classes and modules that -wish to be bound to a global package name must be able to do the -C<Package> role. - -=head2 Hierarchical types - -A non-scalar type may be qualified, in order to specify what type of -value each of its elements stores: - - my Egg $cup; # the value is an Egg - my Egg @carton; # each elem is an Egg - my Array of Egg @box; # each elem is an array of Eggs - my Array of Array of Egg @crate; # each elem is an array of arrays of Eggs - my Hash of Array of Recipe %book; # each value is a hash of arrays of Recipes - -Each successive C<of> makes the type on its right a parameter of the -type on its left. Parametric types are named using square brackets, so: - - my Hash of Array of Recipe %book; - -actually means: - - my Hash[of => Array[of => Recipe]] %book; - -Because the actual variable can be hard to find when complex types are -specified, there is a postfix form as well: - - my Hash of Array of Recipe %book; # HoHoAoRecipe - my %book of Hash of Array of Recipe; # same thing - -The C<returns> form may be used in subroutines: - - my sub get_book ($key) returns Hash of Array of Recipe {...} - -Alternately, the return type may be specified within the signature: - - my sub get_book ($key --> Hash of Array of Recipe) {...} - -There is a slight difference, insofar as the type inferencer will -ignore a C<returns> but pay attention to C<< --> >> or prefix type -declarations, also known as the C<of> type. Only the inside of the -subroutine pays attention to C<returns>. - -You may also specify the C<of> type as the C<of> trait: - - my Hash of Array of Recipe sub get_book ($key) {...} - my sub get_book ($key) of Hash of Array of Recipe {...} - -=head2 Polymorphic types - -Anywhere you can use a single type you can use a set of types, for convenience -specifiable as if it were an "or" junction: - - my Int|Str $error = $val; # can assign if $val~~Int or $val~~Str - -Fancier type constraints may be expressed through a subtype: - - subset Shinola of Any where {.does(DessertWax) and .does(FloorTopping)}; - if $shimmer ~~ Shinola {...} # $shimmer must do both interfaces - -Since the terms in a parameter could be viewed as a set of -constraints that are implicitly "anded" together (the variable itself -supplies type constraints, and C<where> clauses or tree matching just -add more constraints), we relax this to allow juxtaposition of -types to act like an "and" junction: - - # Anything assigned to the variable $mitsy must conform - # to the type Fish and either the Cat or Dog type... - my Cat|Dog Fish $mitsy = new Fish but { int rand 2 ?? .does Cat - !! .does Dog }; - -=head2 Parameter types - -Parameters may be given types, just like any other variable: - - sub max (int @array is rw) {...} - sub max (@array of int is rw) {...} - -=head2 Generic types - -Within a declaration, a class variable (either by itself or -following an existing type name) declares a new type name and takes -its parametric value from the actual type of the parameter it is -associated with. It declares the new type name in the same scope -as the associated declaration. - - sub max (Num ::X @array) { - push @array, X.new(); - } - -The new type name is introduced immediately, so two such types in -the same signature must unify compatibly if they have the same name: - - sub compare (Any ::T $x, T $y) { - return $x eqv $y; - } - -=head2 Return types - -On a scoped subroutine, a return type can be specified before or after -the name. We call all return types "return types", but distinguish -two kinds of return types, the C<inner> type and the C<of> type, -because the C<of> type is normally an "official" named type and -declares the official interface to the routine, while the C<inner> -type is merely a constraint on what may be returned by the routine -from the routine's point of view. - - our sub lay returns Egg {...} # inner type - our Egg sub lay {...} # of type - our sub lay of Egg {...} # of type - our sub lay (--> Egg) {...} # of type - - my sub hat returns Rabbit {...} # inner type - my Rabbit sub hat {...} # of type - my sub hat of Rabbit {...} # of type - my sub hat (--> Rabbit) {...} # of type - -If a subroutine is not explicitly scoped, it belongs to the current -namespace (module, class, grammar, or package), as if it's scoped with -the C<our> scope modifier. Any return type must go after the name: - - sub lay returns Egg {...} # inner type - sub lay of Egg {...} # of type - sub lay (--> Egg) {...} # of type - -On an anonymous subroutine, any return type can only go after the C<sub> -keyword: - - $lay = sub returns Egg {...}; # inner type - $lay = sub of Egg {...}; # of type - $lay = sub (--> Egg) {...}; # of type - -but you can use a scope modifier to introduce an C<of> prefix type: - - $lay = my Egg sub {...}; # of type - $hat = my Rabbit sub {...}; # of type - -Because they are anonymous, you can change the C<my> modifier to C<our> -without affecting the meaning. - -The return type may also be specified after a C<< --> >> token within -the signature. This doesn't mean exactly the same thing as C<returns>. -The C<of> type is the "official" return type, and may therefore be -used to do type inferencing outside the sub. The C<inner> type only -makes the return type available to the internals of the sub so that -the C<return> statement can know its context, but outside the sub we -don't know anything about the return value, as if no return type had -been declared. The prefix form specifies the C<of> type rather than -the C<inner> type, so the return type of - - my Fish sub wanda ($x) { ... } - -is known to return an object of type Fish, as if you'd said: - - my sub wanda ($x --> Fish) { ... } - -I<not> as if you'd said - - my sub wanda ($x) returns Fish { ... } - -It is possible for the C<of> type to disagree with the C<inner> type: - - my Squid sub wanda ($x) returns Fish { ... } - -or equivalently, - - my sub wanda ($x --> Squid) returns Fish { ... } - -This is not lying to yourself--it's lying to the world. Having a -different inner type is useful if you wish to hold your routine to -a stricter standard than you let on to the outside world, for instance. - =head1 Properties and traits Compile-time properties are called "traits". The