Reading the value of a variable and the result of a function

Turtles in POOL are active objects composed of member variables, properties and functions. Each turtle-object has its own queue of tasks (a thread). If a turtle's member function is called by another turtle, it is executed in parallel to the code that has called the function. Functions called in this way are treated as tasks and queued in the order as they were called. All instructions that are affecting a turtle's state are also treated as tasks if called by remote turtle, e.g. forward, setpencolor.
Execution of a turtle program is suspended on the first attempt of reading the result of task of another turtle if that result is not yet ready (see examples 1, 2).

In contrast to function calls, reading values of a remote turtle's variables and properies is done within the task of a turtle that is requesting the read operation. No parallel task is created and the result is available immediately. This allows for monitoring of variables and properties of a remote turtle (e.g. pos, pencolor) ), even if that turtle is performing a long-lasting task (see example 3).
In order to synchronize the read operations with a remote turtle tasks, define getter functions like:

to model
  "x := 5
  to getx op :x end
  to getpos op pos end

Example 1:
The program stores outputs from the factorial function in the :y array. Since the items from the array are used only by print :y command, it is possible to run the entire for loop and launch the parallel calculations for each function call within the loop.

to factorial :x
  (print who :x)
  if :x > 1 [op :x * factorial :x - 1]
  op 1

"n := 3
"y := newarray :n
"t := (anewturtles :n)
for [i 1 :n] [:y,:i := (factorial :i+2) @ :t,:i]
print :y

The order of text lines appearing in the output may differ for each run, except the result "{6 24 120}", which always comes at the end.

t1 3
t2 4
t3 5
t1 2
t2 3
t3 4
t1 1
t2 2
t3 3
t2 1
t3 2
t3 1
{6 24 120}

Example 2:
The program stores the output from fn function in the :p variable. Since this result is used only in the last command in the code, it is possible to complete earlier commands before the long-lasting function is finished.

to model :param
  to fn :x
    (print "start "fn :x)
    wait 2000 ;delay (or a time consuming calculations)
    let "result :x * :param
    print "|result ready|
    op :result

"t := (newt $model 2)

print "|call fn|
"p := (fn 5) @ :t

repeat 3 [wait 200 (print "|parallel code| repcount)]

print "wait...
(print "use :p)


call fn
start fn 5
parallel code 1
parallel code 2
parallel code 3
result ready
use 10

Example 3:
The vary_q function is time consuming. Value of the :q variable is changing during the function execution. The program is monitoring these changes in parallel to the function execution.

to model :param
  to vary_q
    repeat 3 [
      wait 200
      "q += 1
      wait 200
    "stop := true

  ;global variables (public):
  "stop := false
  "q := :param

"t := (newt $model 0)
"test := :q @ :t
vary_q @ :t

while not :stop @ :t [
  "n := :q @ :t
  if :test <> :n ["test := :n (print "change :n repcount)]
  wait 10
print "stop


change 1 22
change 2 61
change 3 101

See also:

Local, global and shared variables
Classes and inheritance
@ (access to class members)

Table of Content