in reply to Re: Raku: Function Signatures
in thread Raku: Function Signatures
Thanks for your answer. It helped me make progress in understanding the syntax. The following is what I figured out with your help.
In Raku, you can specify a type for a parameter variable:
sub echo(Int $x) { say $x.^name; say "echo() received $x"; } echo(3); --output:-- Int echo() received 3
However, specifying the type Int will allow you to call the function with both integers and the type object itself Int
sub echo(Int $x) { say $x.^name; } echo(Int); --output:-- Int
The syntax Int:D means you can call the function with instances of the Int class, but not the Int type object:
sub echo(Int:D $x) { say $x.^name; } echo(Int); --output:-- Parameter '$x' of routine 'echo' must be an object instance of type 'Int', not a type object of type 'Int'. Did you forget a '.new'? in sub echo at b.raku line 14 in block <unit> at b.raku line 18
Similarly, you can disallow instances with the syntax Int:U, which only allows you to pass the Int type object:
sub echo(Int:U $x) { say $x.^name; } echo(3); --output:-- Parameter '$x' of routine 'echo' must be a type object of type 'Int', not an object instance of type 'Int'. Did you forget a 'multi'? in sub echo at b.raku line 14 in block <unit> at b.raku line 22
I think the hint in the error message is asking whether you meant to do:
multi sub echo(Int:U $x) { say $x.^name; } multi sub echo(Int:D $x) { say $x.^name; } echo(3);
Next, I tried the syntax Int:D: to see what would happen:
sub echo(Int:D: $x) { say $x.^name; } echo(3); --output:-- ===SORRY!=== Error while compiling /Users/7stud/raku_programs/b.raku Can only use the : invocant marker in the signature for a method at /Users/7stud/raku_programs/b.raku:14 ------> sub echo(Int:D: $x⏏) { expecting any of: constraint
Then I played around with classes and methods, and this is what I came up with:
class Dog { has Str $.name; method bark(Int:D $x) { say self.^name; # self is an implicit variable that refers t +o the invocant say "bark" for 1..$x; } } my $d = Dog.new(name => "Rover"); $d.bark(3); ---output:-- Dog bark bark bark
And:
In Operators, the colon is listed as a comma. It does act like a separator between the two parameter variables in bark(), but the colon does more than that. In Parameter Separators the docs call the colon an invocant marker, and the docs say:class Dog { has Str $.name; method bark($dog: Int:D $x) { say $dog.^name; # $dog is an explicit variable that refers t +o the invocant say $dog.name; say "bark" for 1..$x; } } my $d = Dog.new(name => "Rover"); $d.bark(3); --output:-- Dog Rover bark bark bark
...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. The invocant is the object that was used to call the method, which is usually bound to self. By specifying it in the signature, you can change the variable name it is bound to.
I was unable to actually write something like Dog:D: in my code. Trying different ways of specifying Dog:D: caused errors, for instance the following didn't work:
class Dog { has Str $.name; method bark(Dog:D:dog: Int $x) { say $dog.^name; say $dog.name; say "bark" for 1..$x; } }
Okay, I was able to use the syntax Dog:D: in my code:
class Dog { has Str $.name; method bark(Dog:D: Int:D $x) { say self.^name; say "bark" for 1..$x; } } my $d = Dog.new(name => "Rover"); $d.bark(3);
Specifying Dog:D: means that the invocant of the method (trailing :) has to be a Dog instance (Dog:D). This won't work:
class Dog { has Str $.name; method bark(Dog:D: Int:D $x) { say self.^name; say "bark" for 1..$x; } } Dog.bark(3); --output:-- Invocant of method 'bark' must be an object instance of type 'Dog', no +t a type object of type 'Dog'. Did you forget a '.new'? in method bark at b.raku line 30 in block <unit> at b.raku line 36
Without the Dog:D:
class Dog { has Str $.name; method bark(Int:D $x) { say self.^name; say "bark" for 1..$x; } } Dog.bark(3); --output:-- Dog bark bark bark
As a result, it looks like you can specify Dog:D: to limit method calls to instances, but you can't use the syntax Dog:D: to change the name of self.
Ahh. Here is the syntax which both limits the method call to instances of the class AND changes the name of self:
class Dog { has Str $.name; method bark(Dog:D $dog: Int:D $x) { say $dog.^name; say $dog.name; say "bark" for 1..$x; } } my $d = Dog.new(name => 'Rover'); $d.bark(3); Dog.bark(3); --output:-- Dog Rover bark bark bark Invocant of method 'bark' must be an object instance of type 'Dog', no +t a type object of type 'Dog'. Did you forget a '.new'? in method bark at b.raku line 30 in block <unit> at b.raku line 39
Therefore, when you read something like the following in the docs:
routine chr multi sub chr(Int:D --> Str:D) multi method chr(Int:D: --> Str:D)
The first line describes a sub/function named chr() that takes one argument of type Int:D, which means an instance of the Int class. In rakudo (the REPL for raku):
32] > chr(99); c
The second line for chr() describes a method, whose invocant (trailing colon) must be an instance of the Int class (Int:D). The syntax Int:D: does NOT specify a positional parameter (even if followed by a variable name!), so the method takes no arguments. In rakudo:
[33] > 99.chr c
The second example on the page class Method uses Int:D: in some code:
Apparently, you can have a free floating method that is not part of a class, and you call it with .&. Then, as described above, Int:D: means the invocant (:) has to be of type Int:D, i.e. an instance of the Int class. And <a> is the way you "quote words", so the argument is 'a', which gets assigned to the parameter variable $b. That example seems to suggest that you can add functionality to any class with a free floating method that specifies the type of the invocant to be of that class.my method m(Int:D: $b){ say self.^name } my $i = 1; $i.&m(<a>); # OUTPUT: «Int»
Cha-ching
|
---|
Replies are listed 'Best First'. | |
---|---|
Re^3: Raku: Function Signatures
by smokemachine (Hermit) on Feb 19, 2024 at 18:34 UTC | |
by 7stud (Deacon) on Feb 20, 2024 at 00:24 UTC |