The common software concept of object is not generally thought to be able model a coin. The idea of a program wielding money, as it would wield some object from the standard Java library probably seems non-sensical to most Java programmers. A context in which this makes sense is where there are callable routines able to serve the caller provided that some payment is made. In such a case money might be passed as an argument. The benefit provided might be valuable information, returned the caller, or external actions that the routine is in a position to effect. Alternatively there may be routines willing to buy information from the caller.
The Keykos programming class would implement some sort of money object as an exercise. This documents one of the designs but is couched in the Keykos jargon. I thought I would show a similar solution in the computer language ‘Scheme’ to show that nothing extraordinary is required of a language. The solutions are very similar but the Keykos solution was implemented in machine language and the bank clients could write in their favorite language. In these Scheme implementations each bank client must write Scheme code to use the bank. Two other more elaborate language implementations are Mark Miller’s description of an implementation in E and an Joule implementation by Dean Tribble. Both of these languages have syntax that makes this sort of thing pretty.
Scheme does not have objects in the sense of a method dispatch mechanism. I use a list of procedures in place of an object.
The scene is a machine that runs a Scheme interpreter. Such an interpreter typically runs a REPL (Read Eval Print Loop). Ours runs at least three REPLs, one for the banker and one each for Alice and Bob who are bank clients. They run on different ttys, of course. The top level name space for each or the REPLs initially contains a named post office box for each of the other REPLs. This allows controlled transmission of Scheme values across REPLs.
The code below uses Rees’ seal and unseal—the values down thru new-seal defined here and explained here.
First perhaps the conceptually simplest bank:
(define (bank n) (let* ((clan-seal (new-seal))(cseal (car clan-seal))(cunseal (cadr clan-seal)) (nb (lambda (v) (let ((c (new-cell))) (cell-set! c v) (cseal c))))) (list (nb n) (lambda (a b) ; empty b into a (let ((ar (cunseal a))(br (cunseal b))) (cell-set! ar (+ (cell-ref ar) (cell-ref br))) (cell-set! br 0))) (lambda (a n) ; new coin of value n from a (let* ((ar (cunseal a)) (ina (cell-ref ar)) (dv (if (< ina n) ina n))) (cell-set! ar (- ina dv)) (nb dv))) (lambda (a) ; Query value (let ((ar (cunseal a))) (cell-ref ar))))))Each invocation of bank yields a new bank in the form of a list of:
(ylppa (bank 1000000) (lambda (a0 empty-into split bq) (write (bq a0)) (newline) ; => 1000000 prime account has $1000000 (let* ((a1 (split a0 42)) (a2 (split a1 100))) ; Split off $42 into account a1; All of that into a2 (write (list (bq a0)(bq a1)(bq a2))) (newline) ; respective balances = 999958 0 42 (empty-into a0 a2) (list (bq a0)(bq a1)(bq a2))))) ; respective balances = 1000000 0 0This version has several things wrong. The banker, who writes the code that defines bank is in a position to damage his clients, beyond classic bank-fraud. Suppose that one of the functions returned by the invocation of bank includes a construct such as (car 2). This is an error but the Scheme report says that errors need not be reported. In encourages reports of such errors but does not specify to whom the report is delivered. Most Scheme implementations report the error to the top level REPL, perhaps arranged so that ......
If you are buying something even much cheaper than gum see DSR.