Range Over Channels in Ada
with Ada.Text_IO;
procedure Range_Over_Channels is
package IO renames Ada.Text_IO;
type String_Access is access String;
type String_Array is array (Positive range <>) of String_Access;
task type Channel is
entry Put (Item : in String);
entry Get (Item : out String);
entry Close;
end Channel;
task body Channel is
Queue : String_Array (1 .. 2);
Count : Natural := 0;
Closed : Boolean := False;
begin
loop
select
when Count < Queue'Length =>
accept Put (Item : in String) do
Count := Count + 1;
Queue (Count) := new String'(Item);
end Put;
or
when Count > 0 =>
accept Get (Item : out String) do
Item := Queue (1).all;
Queue (1 .. Count - 1) := Queue (2 .. Count);
Count := Count - 1;
end Get;
or
accept Close do
Closed := True;
end Close;
or
terminate;
end select;
exit when Closed and Count = 0;
end loop;
end Channel;
Ch : Channel;
begin
-- We'll iterate over 2 values in the Channel.
Ch.Put ("one");
Ch.Put ("two");
Ch.Close;
-- This loop iterates over each element as it's
-- received from the Channel. Because we closed the
-- channel above, the iteration terminates after
-- receiving the 2 elements.
loop
declare
Elem : String (1 .. 3);
begin
select
Ch.Get (Elem);
IO.Put_Line (Elem);
else
exit;
end select;
end;
end loop;
end Range_Over_Channels;
This Ada code demonstrates a similar concept to the original example, using Ada’s tasking model to simulate channels. Here’s a breakdown of the code:
We define a
Channel
task type that can store and retrieve strings.The
Channel
task uses aString_Array
to store the queue items, with a maximum capacity of 2.The main procedure puts two strings into the channel and then closes it.
We use a loop with a
select
statement to iterate over the channel’s contents, which is analogous to therange
loop in the original example.The loop exits when there are no more items to retrieve from the channel.
This example shows how to implement a simple producer-consumer pattern in Ada using tasks. While Ada doesn’t have built-in channels like Go, we can achieve similar functionality using tasks and protected objects.
To run this program, save it as range_over_channels.adb
and compile it with an Ada compiler:
$ gnatmake range_over_channels.adb
$ ./range_over_channels
one
two
This example also demonstrates that it’s possible to close a non-empty channel (task in this case) but still have the remaining values be received.