I have an Ada task, Do_Something
, that needs to "invoke" itself. The way I think of it coming from C++, I have a thread running void Do_Something()
and sometimes void Do_Something()
needs to spawn more threads that also run void Do_Something()
.
Ada (which I'm learning) doesn't like that. This seems to be a M(non)WE:
task body A_Task is
new_task: access A_Task;
my_level: Natural;
begin
accept Do_Something(level: in Natural) do
my_level := level + 1;
end Do_Something;
if my_level < 4 then
new_task := new A_Task;
new_task.Do_Something(my_level);
end if;
end A_Task;
GNAT at least doesn't like this, reporting an error at new_task.Do_Something(my_level);
because
task type cannot be used as type mark within its own spec or body
Yet this is easily circumvented by adding a procedure like this outside the task:
procedure Circumvent(level: Natural) is
new_task: access A_Task;
begin
new_task := new A_Task;
new_task.Do_Something(level + 1);
end Circumvent;
then modifying the if
statement in A_Task
's body to this:
if my_level < 4 then
Circumvent(my_level);
end if;
This latter version passes GNAT (now we have a M***W***E) and the program runs just fine, even in a non-trivial example I was playing with last night.
This workaround seems so straightforward that I don't understand why the compiler should raise the first error at all! I imagine I must be attacking this problem in completely the wrong way. Is this considered good Ada technique, and if not, what would be the Ada-like way to do this sort of thing?