7stud has asked for the wisdom of the Perl Monks concerning the following question:

Dear Monks

In the Raku docs, I see things like the following:

method Capture(Mu:D: --> Capture:D)

What does Mu:D: mean? It looks like the docs are trying to say that Capture() takes an argument of type Mu:D: and returns a type Capture:D. What is D and what is D: ?

And, how would someone look up the syntax Mu:D:?

Replies are listed 'Best First'.
Re: Raku: Function Signatures
by choroba (Cardinal) on Feb 16, 2024 at 18:03 UTC
    The :D is described in Constraining argument definiteness (took me a while to find).

    I guess the colon after D is the infix : operator, but I'm not 100% sure.

    Mu is the base class of the class hieararchy, see Mu.

    map{substr$_->[0],$_->[1]||0,1}[\*||{},3],[[]],[ref qr-1,-,-1],[{}],[sub{}^*ARGV,3]

      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&#9167;) { 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:

      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
      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:

      ...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:

      my method m(Int:D: $b){ say self.^name } my $i = 1; $i.&m(<a>); # OUTPUT: «Int»
      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.

      Cha-ching

        You could also do method bark(Dog:D \dog: Int:D $x) {