πŸ“˜ The closed method in Perl 6 channels

The Channel class also defines a method that checks on whether the channel is closed. This method is called closed.

my $c = Channel.new;
say "open" if !$c.closed; # is openΒ 

$c.close;
say "closed" if $c.closed; # closed

Despite the simplicity of using the method, it in fact returns not a simple Boolean value but a promise object (a variable of the Promise class). A promise (we will talk about this later) can be either kept or broken. Thus, if the channel is open, the closed promise is not yet kept; it is only given (or planned).

Promise.new(status => PromiseStatus::Planned, …) 

After the channel is closed, the promise is kept.

Promise.new(status => PromiseStatus::Kept, …) 

You can see the state of the promise above in its status field.

πŸ“˜ The list method in Perl 6 channels

The list method accompanies the previously seen methods and returns everything that is left unread in the channel.

my $c = Channel.new;Β 

$c.send(5);
$c.send(6);Β 

$c.close;
say $c.list; # (5 6)

The method blocks the programme until the channel is open, thus it is wise to close it before calling the list method.

πŸ“˜ The in and at methods in Perl 6 promises

The other two factory methods, Promise.in and Promise.at, create a promise, which will be kept after a given number of seconds or by a given time. For example:

my $p = Promise.in(3); 

for 1..5 {
Β Β Β  say $p.status;
Β Β Β  sleep 1;
}

The programme prints the following lines.

Planned 
Planned 
Planned 
Kept 
Kept 

That means that the promise was kept after three seconds.

πŸ“˜ Read and write in Perl 6 channels

In Perl 6, there is a predefined class Channel, which includes, among the others, the send and the receive methods. Here is the simplest example, where an integer number first is being sent to the channel $c and is then immediately read from it.

my $c = Channel.new;
$c.send(42);
say $c.receive; # 42

A channel can be passed to a sub as any other variable. Should you do that, you will be able to read from that channel in the sub.

my $ch = Channel.new;
$ch.send(2017);
func($ch);Β 

sub func($ch) {
Β Β Β  say $ch.receive; # 2017
}

It is possible to send more than one value to a channel. Of course, you can later read them all one by one in the same order as they were sent.

my $channel = Channel.new;Β 

# A few even numbers are sent to the channel.
for <1 3 5 7 9> {
Β Β Β  $channel.send($_);
}Β 

# Now, we read the numbers until the channel has them.
# "while @a -> $x" creates a loop with the $x as a loop variable.
while $channel.poll -> $x {
Β Β Β  say $x;
}Β 

# After the last available number, Nil is returned.
$channel.poll.say; # Nil

In the last example, instead of the previously used receive method, another one is used: $channel.poll. The difference lies in how they handle the end of the queue. When there are no more data in the channel, the receive will block the execution of the programme until new data arrive. Instead, the poll method returns Nil when no data are left.

To prevent the programme from hanging after the channel data is consumed, close the channel by calling the close method.

$channel.close;
while $channel.receive -> $x {
Β Β Β  say $x;
}

Now, you only read data, which are already in the channel, but after the queue is over, an exception will occur: Cannot receive a message on a closed channel. Thus either put a try block around it or use poll.

$channel.close;
try {
Β Β Β  while $channel.receive -> $x {
Β Β Β Β Β Β Β  say $x;
Β Β Β  }
}

Here, closing a channel is a required to quit after the last data piece from the channel arrives.