Why are arrays passed as arguments mutable but scalars are not?

Viewed 223

Got this:

#! /usr/bin/env raku
use v6;

multi blah (@arg) { @arg = 7; }
multi blah ($arg) { $arg = '3'; }

my @array = 1, 2, 3;
blah @array;
say @array;

my $string = 'onetwothree';
blah $string;
say $string;

Get this:

[7]
Cannot assign to a readonly variable or a value
  in sub blah at ./chop.raku line 5
  in block <unit> at ./chop.raku line 12

I found this behavior surprising, particularly the ability to change to the array outside of the scope of the function.

Can someone please explain why I can change an array argument passed to a function but not a scalar? And is there a way to make arrays read only when passed to a function? Is there any way to make a scalar passed to a function mutable?

1 Answers

Can someone please explain why I can change an array argument passed to a function but not a scalar?

Arguments passed to a function are read-only (by default; more on that below) and so generally can't be changed. The reason that you can modify the Array is that Arrays are, themselves, mutable (see the Lists, sequences, and arrays page in the docs for details). This means that, even though you can't change the Array itself, you can still change the values in the Array.

And is there a way to make arrays read only when passed to a function?

The List is Raku's immutable type for positional data (sort of; it's not deeply immutable, but that's beyond the scope here). If you pass a List into a function, the function won't be able to modify the contents of that list. For example, this code throws an error:

my @l is List = (1, 2, 3);
sub f(@var) { @var[1] = 42 }
f @l;

Is there any way to make a scalar passed to a function mutable?

There are two ways, depending on what sort of mutability you want: you can use either the is rw and is copy traits. For example, you might declare a function like so:

sub f($a is copy, $b is rw) {...}

That declaration allows &f to modify both $a and $b. But for $a, &f is modifying its own local copy and won't have any effect on the value its callers see for $a. With $b, however, &f is modifying shared state and any changes it makes to $b will be visible even outside the scope of &f.

Related