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

Dear Monks,

Here's an example that uses the topic variable $_

use v6.d; sub go(Int $x where 1 < $_ < 9) { # $_ refers to $x say $x; } go(3); go(0); --output:-- 3 Constraint type check failed in binding to parameter '$x'; expected an +onymous constraint to be met but got Int (0) in sub go at b.raku line 4 in block <unit> at b.raku line 9

I've also seen examples that use a * instead of $_

sub go(Int $x where 1 < * < 9) { say $x; } go(3); go(0); --output:-- 3 Constraint type check failed in binding to parameter '$x'; expected an +onymous constraint to be met but got Int (0) in sub go at b.raku line 4 in block <unit> at b.raku line 9

But * and $_ do not appear to be synonyms because * doesn't work all the time:

for <a b c> {say $_}; # shorter version: for <a b c> {.say} for <a b c> {say *}; --output:-- a b c * * *

Here is another example in the docs that uses *:

sub MAIN( Str $file where *.IO.f = 'file.dat', Int :$length = 24, Bool :$verbose ) { say $length if $length.defined; say $file if $file.defined; say 'Verbosity ', ($verbose ?? 'on' !! 'off'); }

In that example, I can replace * with $_ or $file, and there is no error, and I get the same output. (I don't understand the where clause because $file.IO.f tests whether $file is a file and returns True or False, so the where clause evaluates to something like True = 'file.dat'. What does that do? Ahh, nevermind: 'file.dat' is the default value, and the parameter variable is $file where $file.IO.f. My tests show that the default value gets assigned to $file before the file test. It would be clearer if you could write  Str $file = 'file.dat' where *.IO.f but that results in an error. )

Here's an example that calls first() on a list/array, which allows you to look for the first() thing that matches some condition:

class Foo { method bar( $self: ){ "baz" } }; say Foo.^methods.first(*.name eq 'bar').signature ~~ :($: *%) ; # OUTPUT: «True&#9252;»

If I replace the * with $_, I get an error.

I can't find anything in the docs about the use of * in the examples I posted.

Replies are listed 'Best First'.
Re: Raku: * v. $_ (asterisk v. the topic variable)
by Athanasius (Archbishop) on Feb 19, 2024 at 07:06 UTC

    Hello 7stud,

    Consider the following:

    16:46 >raku -e "for 1 .. * { qq[$_ is { $_.^name }].put; last if $_ >= + 3; }" 1 is Int 2 is Int 3 is Int 16:46 >

    $_ is the topic variable which, as in Perl, acts like a pronoun: we can read the code as “for each value from 1 to infinity, print it and its type, ...” The topic variable $_ is documented in https://docs.raku.org/language/variables#The_$__variable.

    The star, on the other hand, is not a variable, but rather an object — specifically, an instance of Raku’s built-in Whatever class. Its meaning depends on the context in which it is used. In this case it is being used as the end-point of a range, so its meaning is defined by the Range class, which interprets it as Inf (infinity). This use of the star in Raku is documented in https://docs.raku.org/type/Whatever.

    So although $_ and * can sometimes be used interchangeably, they are in fact quite different things.

    Hope that helps,

    Athanasius <°(((><contra mundum סתם עוד האקר של פרל,

      Thanks! I do think the * is prettier than $_. :)

      According to the Whatever docs, if you call a method on * then that creates a lambda (anonymous function):

      <a b c>.map: *.uc; # same as <a b c>.map: -> $char { $char.uc }

      Let's test that out on one of the examples in my question. I'll test whether:

      Str $file where *.IO.f = 'file.dat',

      ...is the same as:

      Str $file where -> $x {$x.IO.f} = 'file.dat',

      Here's the full code with a file name, a.txt, that exists in the current directory:

      #b.raku sub MAIN( Str $file where -> $x {$x.IO.f} = 'a.txt', Int :$length = 24, Bool :$verbose ) { say $length if $length.defined; say $file if $file.defined; say 'Verbosity ', ($verbose ?? 'on' !! 'off'); } --output:-- $ raku b.raku 24 a.txt Verbosity off $ raku b.raku --verbose --length=7 a.raku 7 a.raku Verbosity on

      It looks to me like when you specify a code block on the right of where, the code block is called with the term to the left of where as the argument.

      I don't think the if statements on the end of $length and $file actually do anything: with those default values both variables will be defined.