In object-oriented programming an object is active when its state depends on clock. Usually an active object encapsulates a task that updates the object's state. To the outer world the object looks like a normal object with methods that can be called from outside. Implementation of such methods must have a certain synchronization mechanism with the encapsulated task in order to prevent object's state corruption.

A typical instance of an active object is an animation widget. The widget state changes with the time, while as an object it has all properties of a normal widget.

The task

Implement an active integrator object. The object has an input and output. The input can be set using the method Input. The input is a function of time. The output can be queried using the method Output. The object integrates its input over the time and the result becomes the object's output. So if the input is K(t) and the output is S, the object state S is changed to S + (K(t1) + K(t0)) * (t1 - t0) / 2, i.e. it integrates K using the trapeze method. Initially K is constant 0 and S is 0.

In order to test the object:

 set its input to sin (2π f t), where the frequency f=0.5Hz. The phase is irrelevant.
 wait 2s
 set the input to constant 0
 wait 0.5s
Verify that now the object's output is approximately 0 (the sine has the period of 2s). The accuracy of the result will depend on the OS scheduler time slicing and the accuracy of the clock.

 
integrater = .integrater~new(.routines~sine)   -- start the integrater function
call syssleep 2
integrater~input = .routines~zero              -- update the integrater function
call syssleep .5
 
say integrater~output
integrater~stop          -- terminate the updater thread
 
::class integrater
::method init
  expose stopped start v last_v last_t k
  use strict arg k
  stopped = .false
  start = .datetime~new   -- initial time stamp
  v = 0
  last_v = 0
  last_t = 0
  self~input = k
  self~start
 
-- spin off a new thread and start updating.  Note, this method is unguarded
-- to allow other threads to make calls
::method start unguarded
  expose stopped
 
  reply  -- this spins this method invocation off onto a new thread
 
  do while \stopped
    call sysSleep .1
    self~update    -- perform the update operation
  end
 
-- turn off the thread.  Since this is unguarded,
-- it can be called any time, any where
::method stop unguarded
  expose stopped
  stopped = .true
 
-- perform the update.  Since this is a guarded method, the object
-- start is protected.
::method update
  expose start v last_v t last_t k
 
  numeric digits 20   -- give a lot of precision
 
  current = .datetime~new
  t = (current - start)~microseconds
  new_v = k~call(t)    -- call the input function
  v += (last_v + new_v) * (t - last_t) / 2
  last_t = t
  last_v = new_v
  say new value is v
 
-- a write-only attribute setter (this is GUARDED)
::attribute input SET
  expose k last_t last_v
  self~update          -- update current values
  use strict arg k  -- update the call function to the provided value
  last_t = 0
  last_v = k~call(0)  -- and update to the zero value
 
-- the output function...returns current calculated value
::attribute output GET
  expose v
  return v
 
::routine zero
  return 0
 
::routine sine
  use arg t
  return rxcalcsin(rxcalcpi() * t)
 
::requires rxmath library
 
 