Search code examples
variable-assignmentrakuvariable-binding

Really binding an argument to a parameter? (Perl6)


The Perl6 docs state "By default, parameters are bound to their argument and marked as read-only." But running the following code:

# Example 1
sub f1 ( $x ) { say $x.VAR.WHAT; say $x.WHAT; say $x }
f1(1);

yields:

(Scalar)
(Int)
1

while this code:

# Example 2
my $y := 1;
say $y.VAR.WHAT; say $y.WHAT; say $y;

yields:

(Int)
(Int)
1

It's the (Scalar) in the output of Example1 that I do not understand: why is there a Scalar when I supposedly bind the Int 1 - argument to the identifier $x ? It seems as if the value 1 got "assigned" to $x, rather than "bound".


Solution

  • Scalar containers are also used to indicate items, and thus prevent flattening of them. In the absence of a type constraint, the implementation will conservatively wrap the incoming argument into a read-only Scalar container to avoid any unexpected flattening taking place. Contrast this:

    sub foo($x) {
        my @a = $x;
        say @a.elems;
    }
    foo([1,2,3]);
    

    Which outputs 1 (no flattening), with a sigilless binding:

    sub foo(\x) {
        my @a = x;
        say @a.elems;
    }
    foo([1,2,3])
    

    Which outputs 3, since no item context is imposed. Were the Scalar container not there, both would output 3.

    In the presence of a non-Iterable type constraint, this wrapping will be omitted. Thus writing:

    sub f1(Int $x) {
        say $x.VAR.WHAT;
        say $x.WHAT;
        say $x
    }
    f1(1)
    

    Will output:

    (Int)
    (Int)
    1
    

    With .VAR simply yielding identity on a non-container.