diff --git a/doc/Language/perl-op.rakudoc b/doc/Language/perl-op.rakudoc index 543417329..005931831 100644 --- a/doc/Language/perl-op.rakudoc +++ b/doc/Language/perl-op.rakudoc @@ -52,7 +52,7 @@ also used for method calls. So Perl's C«$arrayref->[7]» becomes Raku's C<$arrayref.[7]> and C«$user->name» becomes C<$user.name>. Note that dereferencing is rare in Raku. -Raku uses the C<->> to attach L|/type/Signature>s to +Raku uses the C«->» to attach L|/type/Signature>s to L|/type/Block>s. =head2 Auto-increment and auto-decrement diff --git a/doc/Language/pod.rakudoc b/doc/Language/pod.rakudoc index f075f09f7..ce0a5e444 100644 --- a/doc/Language/pod.rakudoc +++ b/doc/Language/pod.rakudoc @@ -550,9 +550,16 @@ C C +If the enclosed code itself contains an unmatched C«>», +enclose it in C +=for code :lang +C«sub f(Int --> Int) {}» + +C«sub f(Int --> Int) {}» + =head2 Links -To create a link enclose it in C>: +To create a link enclose it in C> =for code :lang Raku homepage L diff --git a/doc/Language/signatures.rakudoc b/doc/Language/signatures.rakudoc index 5971b7c43..7cf14b5bb 100644 --- a/doc/Language/signatures.rakudoc +++ b/doc/Language/signatures.rakudoc @@ -56,7 +56,6 @@ multi stuff(Int) { 3 } multi stuff(Complex) { 66 } say stuff($_) for (33, ⅓, i, 48); # OUTPUT: «58␤43␤66␤3␤» - However, you can't use C or C as literals in signatures since they will always succeed (or fail). A warning will be issued if you do so: @@ -99,15 +98,20 @@ L|/type/Signature> literals can contain string/numeric literals my $sig = :('Þor', Str, Int); say <Þor Hammer 1> ~~ $sig; # OUTPUT: «True␤» -And they can also contain the invocant marker, explained in the next section: +Signatures can contain a named L, +which I any extra named arguments into one big hash. +It can have any name; conventionally, it's an underscore: - class Foo { - method bar( $self: ){ "baz" } - }; - say Foo.^methods.first(*.name eq 'bar').signature ~~ :($: *%) ; - # OUTPUT: «True␤» + my $sig = :($p, :$n, *%_); +Signatures can also contain a slurpy positional parameter +(which must be the last of all positional parameters); +it slurps up any extra positional arguments into one big array. +The slurpy positional parameter can be one of L: + my $sig = :($p, :$n, **@_); # keep arguments the way they are + my $sig = :($p, :$n, *@_); # flatten any iterable arguments + my $sig = :($p, :$n, +@_); # flatten the argument if it is _one_ iterable, else act like **@_ =head1 Parameter separators @@ -117,9 +121,9 @@ commas. my $sig = :($a, @b, %c); sub add($a, $b) { $a + $b }; -As an exception the first parameter may be followed by a colon instead +As an exception, the first parameter may be followed by a colon instead of a comma to mark the invocant of a method. This is done in order to -distinguish it from what would then be a regular positional parameter. +distinguish it from what would otherwise be a regular positional parameter. The invocant is the object that was used to call the method, which is usually bound to L|/routine/self>. By specifying it in the signature, you can change the variable name it is bound to. @@ -132,6 +136,11 @@ change the variable name it is bound to. } } say Foo.whoami; # OUTPUT: «Well I'm class Foo, of course!␤» + say Foo.^methods.first(*.name eq 'whoami').signature ~~ :($: *%) ; # OUTPUT: «True␤» + +Another exception is the L|/language/Signatures#The_;;_separator>, +which can take the place of one comma in a L signature +to declare that the subsequent parameters should not contribute to its precedence in multiple dispatch. A further exception is the L|/language/Signatures#The_;;_separator>, which can be used in L signatures to declare that all subsequent parameters should not @@ -373,10 +382,10 @@ known collectively as I: say Int ~~ Any:_; # OUTPUT: «True␤» # Checking a subset - subset Even of Int where * // 2; - say 3 ~~ Even:D; # OUTPUT: «True␤» + subset Even of Int where * %% 2; + say 3 ~~ Even:D; # OUTPUT: «False␤» say 3 ~~ Even:U; # OUTPUT: «False␤» - say Int ~~ Even:U; # OUTPUT: «True␤» + say Int ~~ Even:U; # OUTPUT: «Use of uninitialized value of type Int in numeric context␤...␤True␤» # Checking an object instance say 42 ~~ Any:D; # OUTPUT: «True␤» @@ -424,9 +433,9 @@ positional or named, gets no value I. f Nil; # OUTPUT: «Nil␤answer␤» C<$a> has 42 as its default value. With no value, C<$a> will be assigned the -default value declared in the L|/type/Signature>. However, in the second case, it +default value declared in the L|/type/Signature>. However, in the second case, the parameter C<$a> I receive a value, which happens to be L|/type/Nil>. Assigning L|/type/Nil> to -any variable resets it to its default value, which has been declared as +any I resets it to its default value, which for C<$b> has been declared as C<'answer'> by use of the I trait. That explains what happens the second time we call C. Routine parameters and variables deal differently with default value, which is in part clarified by the different way default values are @@ -480,37 +489,42 @@ so that even an instantiated L|/type/Failure> acts as an undefined va =head2 Constraining signatures of L|/type/Callable>s -:u - -whitespace allowed): +The signature of a L parameter can be constrained by +specifying a L literal right after the parameter +(no whitespace allowed): + =begin code :skip-test sub apply(&l:(Int:D --> Int:D), Int:D \n) { l(n) } - sub identity(Int:D \i --> Int:D) { i } sub double(Int:D \x --> Int:D) { 2 * x } + say apply &double, 10; # OUTPUT: «20␤» - say apply &identity, 10; # OUTPUT: «10␤» - say apply &double, 10; # OUTPUT: «20␤» + sub general-double(Numeric:D \x --> Numeric:D) { 2 * x } + say apply &general-double, 10; # OUTPUT: «Signature constraint check failed(…)␤» + =end code -Typed L also work with -constrained callable parameters. +This shorthand syntax for constraining the signature of C<&l> +is only available because it has the C<&> sigil. +For C<$>-sigiled callable parameters, you need to use the long version with C: + + sub apply($l where .signature ~~ :(Int:D --> Int:D), Int:D \n) { + $l(n) + } + +You can also pass typed L +for constrained callable parameters like C<&l> or C<$l>: =for code :preamble say apply -> Int:D \x --> Int:D { 2 * x }, 3; # OUTPUT: «6␤» say apply -> Int:D \x --> Int:D { x ** 3 }, 3; # OUTPUT: «27␤» -Note that this shorthand syntax is available only for parameters with the C<&> -sigil. For others, you need to use the long version: +Constraints without type smileys are also possible. - sub play-with-tens($c where .signature ~~ :(Int, Str)) { say $c(10, 'ten') } - sub by-joining-them(Int $i, Str $s) { $s ~ $i } - play-with-tens &by-joining-them; # OUTPUT: «ten10␤» - play-with-tens -> Int \i, Str \s { s x (1..10).roll mod i }; # OUTPUT: «tenten␤» - - sub g(Num $i, Str $s) { $s ~ $i } - # play-with-tens(&g); # Constraint type check failed + sub play-with-tens(&c:(Int, Str)) { say c(10, 'ten') } + play-with-tens -> Int \i, Str \s { s ~ i } # OUTPUT: «ten10» + play-with-tens -> Int \i, Str \s { s x (1..30).roll mod i} # OUTPUT: «tenten(…)ten␤» =head2 Constraining return types @@ -526,11 +540,12 @@ chain. sub foo(--> Int) { Nil }; say foo.raku; # OUTPUT: «Nil␤» -Type captures are not supported. +A L can also be used +as the return type constraint (see there for details). X«|Syntax,-->» X«|Syntax,Return type arrow» -=head3 Return type arrow: C<-->> +=head3 Return type arrow: C«-->» This form of indicating return types (or constants) in the signature is preferred, since it can handle constant values while the others can't. For @@ -572,10 +587,11 @@ cannot use it in a block either. That is why the pointy arrow form is always preferred. =for code -sub greeting(Str $name) returns Str { say "Hello, $name" } # Valid +sub greeting(Str $name) returns Str { say "Hello, $name" }; # Valid +say &greeting.signature # OUTPUT: «(Str $name --> Str)␤» =for code :skip-test -sub favorite-number returns 42 { } # This will fail. +sub favorite-number returns 42 { }; # This will fail. =head3 C @@ -583,19 +599,22 @@ C is just the real name of the C keyword. =for code sub foo() of Int { 42 }; # Valid +say &foo.signature # OUTPUT: «( --> Int)␤» =for code :skip-test -sub foo() of 42 { }; # This will fail. +sub foo() of 42 { }; # This will fail. -=head3 prefix(C-like) form +=head3 prefix (C-like) form This is similar to placing type constraints on variables like C, except the C<$var> is a definition for a routine. =for code my Int sub bar { 1 }; # Valid +say &bar.signature # OUTPUT: «( --> Int)␤» + =for code :skip-test -my 42 sub bad-answer {}; # This will fail. +my 42 sub bad-answer { }; # This will fail. =head2 X @@ -603,8 +622,8 @@ To accept one type but coerce it automatically to another, use the accepted type as an argument to the target type. If the accepted type is L|/type/Any> it can be omitted. - sub f(Int(Str) $want-int, Str() $want-str) { - say $want-int.^name ~ ' ' ~ $want-str.^name + sub f(Int(Str) $becomes-int, Str() $becomes-str) { + say $becomes-int.^name ~ ' ' ~ $becomes-str.^name } f '10', 10; # OUTPUT: «Int Str␤» @@ -652,6 +671,110 @@ bar(3); =end code +X<|Language,Type capture> +=head1 Type captures + +Type captures allow deferring the specification of a type constraint to the time +the function is called. They allow referring to a type both in the signature and +the function body. + + sub f(::T $p1, T $p2, ::C){ + # $p1 and $p2 are of the same type T, that we don't know yet + # C will hold a type we derive from a type object or value + my C $division = $p1 / $p2; + return sub (T $p1) { + $division * $p1; + } + } + + # The first parameter is Int and so must be the 2nd. + # We derive the 3rd type from calling the operator that is used in &f. + my &s = f(10, 2, Int.new / Int.new); + say s(2); # 10 / 2 * 2 == 10 + +A captured type can be used as the return type constraint +(cf. L): + + sub cast-by-example(Any $x, ::T $example --> T) { T($x) } + sub cast-or-create(Any $x, ::T $example --> T:D) { with $x { T($x) } else { T.new } } + +Captured types can also be used to coerce other parameters to that type +(just like it is done in section L +for fixed types). +For example, this function coerces the second parameter C, which must be of type L|/type/Cool>, +to whichever type the first parameter C has: + + sub accum( ::T \a, T(Cool) \b ) { a += b }; + + my $t = 3; # Int + accum( $t, 5/3 ); # OUTPUT: «4␤» + + my $t = 3.0; # Rat + accum( $t, 5/3 ); # OUTPUT: «4.666667␤» + + my $t = 3.0; # Rat, and the second parameter an Array + accum ( $t, ["x","y"] ); # OUTPUT: «5.0» + +Type captures can also be subject to type constraints. +In the example above, certain nonsensical calls could be prevented by changing +the signature to one of the following: + + =for code :skip-test + (Numeric ::T \a, T(Cool) \b ) + (::T Numeric \a, T(Cool) \b ) + +See also section C +in the type reference for C. + + +X<|Language,positional argument> +X<|Language,named argument> +=head1 Positional vs. named arguments + +An argument can be I or I. By default, arguments are +positional, except slurpy hash and arguments marked with a leading colon C<:>. +The latter is called a L. Check the following signatures +and what they denote: + +=for code :preamble +$sig1 = :($a); # a positional argument +$sig2 = :(:$a); # a named argument of name 'a' +$sig3 = :(*@a); # a slurpy positional argument +$sig4 = :(*%h); # a slurpy named argument + +On the caller side, positional arguments are passed in the same order as the +arguments are declared. + + sub pos($x, $y) { "x=$x y=$y" } + pos(4, 5); # OUTPUT: «x=4 y=5» + +In the case of named arguments and parameters, only the name is used for mapping +arguments to parameters. If a fat arrow is used to construct a +L|/type/Pair> only those with valid identifiers as keys are recognized as +named arguments. + +=for code +sub named(:$x, :$y) { "x=$x y=$y" } +named( y => 5, x => 4); # OUTPUT: «x=4 y=5» + +You can invoke the routine using a variable with the same name as the named +argument; in that case C<:> will be used for the invocation so that the name of +the variable is understood as the key of the argument. + + sub named-shortcut( :$shortcut ) { + say "Looks like $shortcut" + } + named-shortcut( shortcut => "to here"); # OUTPUT: «Looks like to here␤» + my $shortcut = "Þor is mighty"; + named-shortcut( :$shortcut ); # OUTPUT: «Looks like Þor is mighty␤» + +It is possible to have a different name for a named argument than the +variable name: + + sub named(:official($private)) { "Official business!" if $private } + named :official; + + X<|Syntax,*@> X<|Syntax,*%> X<|Language,slurpy argument> @@ -665,8 +788,8 @@ make routines that use them I, and by extension are called variadic arguments. Here we will focus on slurpy parameters, or simply I. An array or hash parameter can be -marked as I by leading single (*) or double asterisk (**) or a -leading plus (+). A slurpy parameter can bind to an arbitrary number of +marked as I by leading single (C<*>) or double asterisk (C<**>) or a +leading plus (C<+>). A slurpy parameter can bind to an arbitrary number of arguments (zero or more), and it will result in a type that is compatible with the sigil. @@ -739,7 +862,7 @@ L, as described in L. -Methods automatically get a C<*%_> slurpy named parameter added if they +L automatically get a C<*%_> slurpy named parameter added if they don't have another slurpy named parameter declared. =head1 Types of slurpy array parameters @@ -775,6 +898,17 @@ a(($_ for 1, 2, 3)); # OUTPUT: «[1, 2, 3]␤» A single asterisk slurpy flattens all given iterables, effectively hoisting any object created with commas up to the top level. +Such flattening can be prevented for individual arguments +by putting them in an L. +This can be done by prepending the sigil C<$> or by applying the C<.item> method: + +=begin code +sub slurp(*@pos) { say @pos; } +my @array = [5,6]; +slurp([1,2], $[3,4], $@array); # OUTPUT: «[1 2 [3 4] [5 6]]␤» +slurp([1,2], [3,4].item, @array.item) # OUTPUT: «[1 2 [3 4] [5 6]]␤» +=end code + =head2 X Slurpy parameters declared with two stars do not flatten any @@ -798,7 +932,6 @@ in the slurpy array. X<|Syntax,+ (Single argument rule slurpy)> =head2 Single argument rule slurpy - A slurpy parameter created using a plus engages the I<"single argument rule">, which decides how to handle the slurpy argument based upon context. Basically, if only a single argument is passed and that argument is @@ -818,73 +951,6 @@ c(($_ for 1, 2, 3)); # OUTPUT: «[1, 2, 3]␤» For additional discussion and examples, see L. -X<|Language,Type capture> -=head1 Type captures - -Type captures allow deferring the specification of a type constraint to the time -the function is called. They allow referring to a type both in the signature and -the function body. - - sub f(::T $p1, T $p2, ::C){ - # $p1 and $p2 are of the same type T, that we don't know yet - # C will hold a type we derive from a type object or value - my C $division = $p1 / $p2; - return sub (T $p1) { - $division * $p1; - } - } - - # The first parameter is Int and so must be the 2nd. - # We derive the 3rd type from calling the operator that is used in &f. - my &s = f(10, 2, Int.new / Int.new); - say s(2); # 10 / 2 * 2 == 10 - -X<|Language,positional argument> -X<|Language,named argument> -=head1 Positional vs. named arguments - -An argument can be I or I. By default, arguments are -positional, except slurpy hash and arguments marked with a leading colon C<:>. -The latter is called a L. Check the following signatures -and what they denote: - -=for code :preamble -$sig1 = :($a); # a positional argument -$sig2 = :(:$a); # a named argument of name 'a' -$sig3 = :(*@a); # a slurpy positional argument -$sig4 = :(*%h); # a slurpy named argument - -On the caller side, positional arguments are passed in the same order as the -arguments are declared. - - sub pos($x, $y) { "x=$x y=$y" } - pos(4, 5); # OUTPUT: «x=4 y=5» - -In the case of named arguments and parameters, only the name is used for mapping -arguments to parameters. If a fat arrow is used to construct a -L|/type/Pair> only those with valid identifiers as keys are recognized as -named arguments. - -=for code -sub named(:$x, :$y) { "x=$x y=$y" } -named( y => 5, x => 4); # OUTPUT: «x=4 y=5» - -You can invoke the routine using a variable with the same name as the named -argument; in that case C<:> will be used for the invocation so that the name of -the variable is understood as the key of the argument. - - sub named-shortcut( :$shortcut ) { - say "Looks like $shortcut" - } - named-shortcut( shortcut => "to here"); # OUTPUT: «Looks like to here␤» - my $shortcut = "Þor is mighty"; - named-shortcut( :$shortcut ); # OUTPUT: «Looks like Þor is mighty␤» - -It is possible to have a different name for a named argument than the -variable name: - - sub named(:official($private)) { "Official business!" if $private } - named :official; X<|Language,argument aliases> =head1 Argument aliases @@ -999,14 +1065,14 @@ Table showing checks of whether an argument was passed for a given parameter: ===============|================|============================|======================== Slurpy | *@array | Don't check using .defined | if not @array Required | $foo | Can't be omitted | (not applicable) - Optional | @bar = default | Pick a suitable default¹ | if @bar =:= default + Optional | @bar = default | Pick a suitable default¹ | if @bar === default =end table -¹ A suitable default is an Object that has a distinct identity, as may be checked by the L|https://docs.raku.org/type/Mu#method_WHICH> method. +¹ A suitable default is an Object that has a distinct identity, as may be checked by the L|/type/Mu#method_WHICH> method. A parameter with a default is always I, so there is no need to mark it with a C. -Then you can use the C<===> L in the body of the routine to check +Then you can use the C<===> L in the body of the routine to check whether this exact default object was bound to the parameter. These examples use names like C to reflect that the C<.WHICH> test invoked by C<===> returns an object of type L|/type/ObjAt>. @@ -1014,7 +1080,7 @@ Example with a positional parameter: =begin code my constant PositionalAt = Positional.new; -sub a (@list = PositionalAt) { say @list === PositionalAt } # here, one can also use =:=, the container identity operator +sub a (@list = PositionalAt) { say @list === PositionalAt } a; # OUTPUT: «True␤» a [1, 2, 3]; # OUTPUT: «False␤» =end code @@ -1023,13 +1089,13 @@ Example with some scalar parameters: =begin code my constant AnyAt = Any.new; -sub b ($x=AnyAt, :$y=AnyAt) { say $x === AnyAt; say $y === AnyAt } # here, =:= would always produce False +sub b ($x=AnyAt, :$y=AnyAt) { say $x === AnyAt; say $y === AnyAt } b 1; # OUTPUT: «False␤True␤» b 1, :2y; # OUTPUT: «False␤False␤» =end code -If your parameters are typed, then the L can be used with -L|https://docs.raku.org/language/functions#Multi-dispatch>s like this: +If your parameters are typed, then the L can be used with +L|/language/functions#Multi-dispatch>s like this: =begin code multi c (Int:U $z) { say 'Undefined' } @@ -1156,23 +1222,23 @@ Consider this example with a named parameter: # both 42 and 「」␤ in sub e at line 1␤» Here it was the I multi that got executed, -because its signature is narrower than the first and does in fact match C, even though $s then stays undefined. -By adding C<;;>, we can lower its precedence: +because its signature is narrower than the first and does in fact match C, even though C<$s> then stays undefined. +By adding C<;;>, we can lower its precedence to match that of the first: - multi f(Int $i) { say "just $i" }; - multi f(Int $i;; Str :$s) { say "both $i and 「$s」" }; - f(42); - # OUTPUT: «Ambiguous call to 'e(Int)'; these signatures all match: + multi baz(Int $i) { say "just $i" }; + multi baz(Int $i;; Str :$s) { say "both $i and 「$s」" }; + baz(42); + # OUTPUT: «Ambiguous call to 'baz(Int)'; these signatures all match: # (Int $i) from line 1␤ (Int $i;; Str :$s) from line 1␤ ...» One could then give the first multi the trait L|/type/Routine#trait_is_default>, whose exact effect is -to break a tie between multiple signatures of the same precedence. +to break a tie between signatures of the same precedence. There is more than one way to control the narrowness (and thereby, precedence) of signatures. Other options include making parameters optional via C or required via C. -The double semicolon C<;;> can also be used in signatures of L. +The double semicolon C<;;> can also be used in signatures of L. Parameterized roles have a so-called "long name" generated from their signature, which can be used for introspection. Only parameters to the left of C<;;> contribute to it. diff --git a/doc/Type/Iterable.rakudoc b/doc/Type/Iterable.rakudoc index 59f13a865..e8243cbbd 100644 --- a/doc/Type/Iterable.rakudoc +++ b/doc/Type/Iterable.rakudoc @@ -68,7 +68,7 @@ C«(, 'c').flat» returns C<('a', 'b', 'c')>, which has three elems. Note that the flattening is recursive, so C<((("a", "b"), "c"), "d").flat> returns C<("a", "b", "c", "d")>, but it does not flatten -itemized sublists: +L sublists: say ($('a', 'b'), 'c').flat; # OUTPUT: «($("a", "b"), "c")␤»