%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % Observable port objects % Author: Peter Van Roy % Date: Nov. 26, 2008 % See section 5.2.1 of CTM (page 351). % We extend the creation of port objects by adding an % observer of the successive internal states of the % port object. We can use this observer, e.g., to % debug a multi-agent system. This is an example of % separation of concerns: the port object's % specification is not changed. % C={NewPortObject Init Fun}: create a port object % with initial state Init and transition function Fun % C={NewPortObjectObserve Init Fun S}: create a port % object with initial state Init, transition function % Fun, and stream S of internal states. %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % Step 1: % We start with the definition of NewPortObject using % FoldL. FoldL implements an accumulator. This is an % example of using a functional building block as a % concurrency pattern. declare fun {NewPortObject Init Fun} Sin Out in thread {FoldL Sin Fun Init Out} end {NewPort Sin} end %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % Step 2: % We extend NewPortObject with an extra argument that % returns a stream of the internal states of the port % object. The new function NewPortObjectObserve is % also defined using FoldL, simply by giving it a % new transition function that keeps track of both the % current state and the end of the state stream. % Note: another possible definition would be to define % a second port and to send the internal states to this % port. This definition is too general since we do not % need the nondeterminism of ports to keep track of % the internal states. declare fun {NewPortObjectObserve Init Fun ?SHead} Sin Out STail in SHead=Init|STail thread {FoldL Sin fun {$ STail#State Msg} State2 STail2 in State2={Fun State Msg} STail=State2|STail2 STail2#State2 end STail#Init Out} end {NewPort Sin} end %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % Example execution % Here is the state transition function for a port % object that implements an up/down counter declare fun {CFun State Msg} case Msg of inc then State+1 [] dec then State-1 [] get(X) then X=State State end end % We define a counter object % The first object is a straightforward counter declare C1={NewPortObject 0 CFun} % Send messages to the first object {Send C1 inc} {Send C1 dec} {Browse {Send C1 get($)}} % We define a second counter with the same behavior % whose internal states are returned as a stream declare C2 S2 in C2={NewPortObjectObserve 0 CFun S2} % Observe the internal states {Browse S2} % Send messages to the second object {Send C2 inc} {Send C2 dec} {Browse {Send C2 get($)}} %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%