Why can't I iterate after an assignment in Raku?

Viewed 126

Given the following code, it seems that I cannot iterate over a Buf if it had been assigned to a variable, unless I cast it to a list, even though it's not a lazy sequence. What gives?

    my $file = open $path, bin => True;
    $_.chr.say for $file.read: 8; # works well

    my $test = $file.read: 8;
    $_.chr.say for $test; # fails with "No such method 'chr' for invocant of type 'Buf[uint8]'"
    $_.chr.say for $test.list; # works well
    $test.is-lazy.say; # False
1 Answers

The reason it fails, is that:

my $test = $file.read: 8;

puts the Buf that is returned by $file.read into a Scalar variable, aka inside a container. And containerized is interpreted by for as itemized, to be considered a single item. So with:

.chr.say for $test;

you're calling the .chr method on the whole Buf, rather than on the individual elements.

There are a number of solutions to this:

  1. make sure there's no container:
my $test := $file.read: 8;

This makes sure there is no container by binding the Buf.

  1. make it look like an array
my @test := $file.read: 8;

Same as 1 basically, make the @test be an alias for the Buf. Note that this should also use binding, otherwise you'll get the same effect as you saw.

  1. make it work like an Iterable
.chr.say for @$test;

By prefixing the @ you're telling to iterate over it. This is basically syntactic sugar for the $test.list workaround you already found.

Re the $test.is-lazy.say, that is False for just about anything, e.g. 42.is-lazy.say; # False, so that doesn't tell you very much :-)

Related