TOTAM has been implemented in AmbientTalk. The system library shipped with AmbientTalk contains the TOTAM implementation under at/lang/totam.at. In order to use TOTAM, you need to load the library and create a TOTAM tuple space as follows:
import /.at.lang.totam;
def myTupleSpace := makeTupleSpace();
A description can be passed in the makeTupleSpace operation in order to activate the scoping mechanism (as we will explain later). To create a tuple or a template, the tuple operation can be used as follows:
// a “hallo” message tuple from wolf.
def halloTuple := tuple: ["Message", “wolf”, “hallo”];
// a template for message tuples from wolf.
def wolfTuples := tuple: ["Message", “wolf”, var: `content];
// a template for any message tuples.
def msgTuples := tuple: ["Message", var: `from, var: `content];
TOTAM provides operations to add and read tuples from the tuple space as follows:
// add tuple to tuple space
myTupleSpace.out(halloTuple);
// get a Message tuple
def aMessageTuple := myTupleSpace.rdp(msgTuples);
// get all Message tuples.
def messageTuples := myTupleSpace.rdg(msgTuples);
The rdp(template) and rdg(template) operations return a tuple or all tuples matching the template in the tuple space if present (without removing), respectively. Note that these operations are non-blocking. The out(tuple) operation to insert a private tuple in the tuple space. In order for applications to insert a public tuple, thereby making it available to other collocated TOTAM systems, the inject: operation is provided.
myTupleSpace.goOnline();
myTupleSpace.inject: halloTuple;
Note that the network facilities are disabled by default, so before injecting something in the network, the goOnline() method must be called on the tuple space. A tuple injected to the network carries the following default propagation protocol.
def defaultPropagationProtocol(){
isolate: {
//receiver-side protocol
def decideEnter(ts) { true };
def doAction(ts){};
def changeTupleContent(ts){self};
def decideStore(ts) {true};
//sender-side protocol
def inScope(senderDescriptor,receiverDescriptor){ true };
def decideDie(ts){false};
};
};
However, other propagation protocols can be created and attached to a tuple before being injected in the network as follows:
//define a new propagation protocol
def blueProtocol := propagationProtocol: {
def inScope(senderDescriptor,receiverDescriptor) {
receiverDescriptor.team == "blue" };
};
// attach the protocol to a tuple
def aBlueTuple := tuple: ["Message", "hallo"]
withPropagationProtocol: blueProtocol;
// inject the tuple to the network
def publication := inject: aBlueTuple;
The propagationProtocol: operation creates a propagation protocol object which extends the default propagation protocol object with other semantics. this sample code shows a protocol based on the operational sketch figure that checks whether the receiver of the tuple is part of the blue team. This is attached to the tuple by means of the tuple:withPropagationProtocol: operation which is then injected into the network. The inject: operation returns a publication object which can be used as follows to remove the tuple from the network.
// sends an antituple to notify the removal of this tuple.
publication.retract();
In order to notify the removal of a tuple, TOTAM sends an antituple for the removed tuple. For every tuple there is (conceptually) a unique antituple with the same format and content, but with a different sign. All tuples injected by an application have positive sign while their antituples have a negative sign. Whenever a tuple and its antituple are stored in the same tuple space, they immediately annihilate one another, i.e. they both get removed from the tuple space. By means of antituples, TOTAM can “unsend” tuples injected to the network.