AN EXAMPLE

A "financial history" supports the following transactions:

receive(amount,source) records that amount (an integer) was
                       received from source (a string)
spend(amount,reason)   records that amount (an integer) was
                       spent for reason (a string)
totalrec(source)       returns the total amount received from
                       source
totalspent(reason)     returns the total amount spent for
                       reason
cashonhand             records the cash on hand (an integer)

There are three global variables representing the state: cashonhand,
inc (a map from source to amount), and exp (a map from reason to
amount).

The Proxy program for this example is contained in the file FINANCE.PRX
and is shown here exactly as contained in the file. Since types are not
declared in Proxy, it is good practice to specify the types of the state
components are shown below.

// state components:

// cashonhand: integer
// inc: map(string,integer)
// exp: map(string,integer)

receive(amount,source) {cashonhand=cashonhand+amount;
                  inc[source]=inc[source,0]+amount;
                  return "ok";};
spend(amount,reason) {if(amount>cashonhand) return "Insufficient funds";
                 cashonhand=cashonhand-amount;
                 exp[reason]=exp[reason,0]+amount;
                 return "ok";};
totalrec(source) {return inc[source,0];};
totalspent(reason) {return exp[reason,0];};
cashonhand=100;
end

The cashonhand is initialized to 100 and is incremented in the receive
function and decremented in the spend function. If the amount to be
spent is greater than the cashonhand, the spend function returns
"Insufficient funds". The map 'inc' consists of a set of ordered pairs
where the first element of a pair is the source of a receipt, and the
second element is the total amount received from this source. The map
'exp' contains the pairs where the first element is the reason for the
expense and the second element is the total amount spent. The default
error return, for example inc[source,0], handles the case where a
source appears for the first time and therefore does not occur as a
domain element in the map. The totalrec and totalspent functions use map
application to return the total amounts received and spent respectively.
Here again, the default error return will return 0 if the source or
reason does not appear in the map.

Another way of writing the program is to leave out the return "ok"
statements in the spend and receive functions. The effect of these
changes is that no output will be obtained when they are invoked,
except in the case of insufficient funds.

A possible sequence of operations follows.

? cashonhand;
 100
? spend(50,"food");
 "ok"
? receive(100,"bank");

 "ok"
? cashonhand;
 150

? spend(100,"food");
 "ok"
? totalspent("food");
 150

? spend(150,"rent");
 "Insufficient funds"

ANOTHER EXAMPLE

An Electronic Mail System (Email) is to be designed to provide
communication between users of the system. The following operations
must be supported:

Signon(u,p) - By giving a valid user name and user-selected password,
              a user should be permitted access to the system.

Signoff(u)  - The user may remove himself from the system

Add(u,n,p)  - The "super" user may supply a name and password in order
              to add a new user to the list of authorized users.

Drop(u,n)   - The "super" user may delete a user name from the list
              of authorized users.

Send(u,t,n) - By giving the text of a message and name of a receiver,
              a user can place a message into a receiver's queue.

Read(u)    - A user can issue a Read command to examine his/her queue.
             The response should be the sender's name and text of the
             first message (if any). Successive reads will return
             additional messages (if any).

Delete(u)  - After reading a message, the user may issue a Delete
             command to delete the message just read.

Reset(u)   - This causes the next Read command to begin at the head
             of the queue.

Notice that the first parameter of each operation represents the
name of the user invoking the operation.

A Proxy program for this application is contained in the file EMAIL.PRX.
This solution illustrates the use of return messages to signal exceptions.
A queue class is first defined with the following operations: read,
write, reset and delete. This class has two instance variables: procd
and remdr, both sequences. procd represents the queue of mail messages
already processed, and remdr represents the queue of messages not
yet read. The queue class acts like a sequential file and can be
used in any application requiring a data structure with these character-
istics. The state components are:

     up (map from user to password)
     uq (map from user to mail-queue)
     so (set of users who are signed on)

// state components

// up: map(string,string)
// uq: map(string,queue)
// so: set(string)

class queue(procd,remdr) {
 read(;x) {
          if(len remdr==0) return "empty queue";
          x=hd remdr;
          remdr=tl remdr;
          procd=procd conc [x];
          return x;}
 write(msg) {remdr=remdr conc [msg];}
 reset() {remdr=procd conc remdr;
          procd=[];}
 delete() {if(len procd==0) return "empty queue";
           procd=butlast procd;} };

up={"super" -> "super"};           // initialize super user with pw "super"
uq={"super" -> new queue([],[])};  // initialize mail-queue for super user
                                    // can send mail to him
struct mail {sender,text;};

add(u,n,pw) {if (u != "super") return {"not authorized",u};
             uq[n]=new queue([],[]); // initializes mail-queue
             up[n]=pw;               // initializes password
             return "ok";};
drop(u,n) {if (u != "super") return {"not authorized",u};
           if (n notin dom up) return {"unknown user",n};
           up=up ds {n};                // remove user and password
           uq=uq ds {n};                // remove user and mail-queue
           if(n in so) so=so diff {n};  // if user signed on, sign
           return "ok";};                // him off
signon(u,pw) {if (u notin dom up) return {"unknown user", u};
             if (up[u,""] != pw) return "incorrect password";
              so=so U {u};              // sign him on
              return "ok";};
signoff(u) {if (u notin so) return {"not signed on",u};
            so=so diff {u};             // sign him off
            return "ok";};
send(u,t,r;x) { if (u notin so) return {"not signed on",u};
             if (r notin dom up) return {"unknown user",r};
             x=uq[r];
             x.write(new mail(u,t));      // create mail and send
             return "ok";};
read(u;x) {if (u notin so) return {"not signed on",u};
                x=uq[u];
         return x.read;};                // read mail
reset(u;x) {if (u notin so) return {"not signed on",u};
                 x=uq[u];
          x.reset;                       // reset mail-queue
          return "ok";};
delete(u;x) {if (u notin so) return {"not signed on",u};
                  x=uq[u];
           x.delete;                     // delete mail
           return "ok";};
s

so = {};
end

The following sequence of messages and responses shows the application
of the Email operations.

? add("super","joe",123);
 "ok"
? add("super","mike",456);
 "ok"
? signon("joe",123);
 "ok"
? signon("mike",455);
 "incorrect password"
? signon("mike",456;
 "ok"
? send("joe","hello","mike");
 "ok"
? send("joe","there","mike");
 "ok"
? send("joe","meet me","tom");
 {"unknown user","tom"}
? read("mike");
 < "joe", "hello" >
? read("mike");
 < "joe", "there" >
? read("mike");
 "empty queue"
? reset("mike");
 "ok"
? read("mike");
 < "joe", "hello">
? delete("mike");
 "ok"
? read("mike");
 < "joe", "there" >
? reset("mike");
 "ok"
? read("mike");
 < "joe", "there" >
? drop("joe","mike");
 {"not authorized","joe"}
? signoff("joe");
 "ok"
