setrakubag

total method and the sigil of a Bag variable in Perl 6


We can use the total method to know the sum of all the weights in a Bag.

> my $b = (1,2,1).Bag
Bag(1(2), 2)
> $b.total
3

But if we use the % sigil instead of $ for our Bag, we get an error message.

> my %b = (1,2,1).Bag
{1 => 2, 2 => 1}
> %b.total
No such method 'total' for invocant of type 'Hash'. Did you mean 'cotan'?
  in block <unit> at <unknown file> line 1

If %b is explicitly converted to Bag before total, it works:

> %b.Bag.total
3

The question: I used to think that with Set, Bag, SetHash etc., using the % sigil is preferable. Am I wrong?


Solution

  • Bind instead of assign

    my %b := (1,2,1).Bag;
    say %b.total
    

    Binding (with :=) binds the right hand side directly to the left hand side. In this case a value that does the Associative role gets bound to %b.

    Or assign to a Bag

    Assigning (with =) assigns (copies) values from the right hand side into the container on the left hand side.

    You can assign after first binding to a Bag as follows.

    Immediately prior to an assignment a my declarator will bind a suitable container to the declared variable. By default it will be a Hash container if the variable has a % sigil.

    But you can specify a variable is bound to some other type of container that's compatible with its sigil:

    my %b is Bag = 1,2,1;
    say %b.total
    

    With this incantation you need to use = because, by the time that operator is encountered %b has already been bound to a Bag and now you need to assign (copy) into the Bag.

    This way you get the simplicity of just providing a list of values (no explicit keys or Bag coercer/constructor necessary) because = is interpreted according to the needs of the container on its left, and a Bag choses to interpret the RHS of = as a list of keys whose occurrence count is what matters to it.