Private References and Bank Accounts
Encapsulation via closures
OCaml references are more flexible than those in conventional languages. By capturing a reference in a closure, we can create private, persistent state - analogous to objects in OOP.
makeAccount
exception TooMuch of int
let makeAccount initBalance =
let balance = ref initBalance in
let withdraw amt =
if amt > !balance then
raise (TooMuch (amt - !balance))
else begin
balance := !balance - amt;
!balance
end
in
withdraw
(* val makeAccount : int -> int -> int = <fun> *)
Key points:
balanceis a private reference created insidemakeAccount.withdrawis the only function with access tobalance- it is captured in a closure.- The balance cannot be modified except by calling
withdraw. - An exception
TooMuchprevents overdrafts; the amount by which the withdrawal exceeds the balance is carried in the exception. - Deposits are withdrawals of a negative amount.
The begin/end block
The syntax begin ... end is equivalent to ( ... ) - it groups expressions into a single expression. In withdraw, it sequences the assignment and the return of the new balance:
begin
balance := !balance - amt;
!balance
end
Two independent accounts
let student = makeAccount 500
let director = makeAccount 4000000
student 5 (* => 495 *)
director 150000 (* => 3850000 *)
student 500 (* raises TooMuch 5 *)
Each call to makeAccount creates a fresh reference cell. The two accounts are completely independent. Neither account holder can access the other’s balance - the encapsulation is enforced by the language, not by convention.
Analogy to OOP
| Concept | In OOP (e.g. Java) | In OCaml |
|---|---|---|
| Private state | Instance variables | Captured ref cells |
| Methods | Object methods | Returned closure functions |
| Constructor | Class constructor | makeAccount function |
| Encapsulation | private keyword | Lexical scoping |
If the returned function is discarded, the reference becomes unreachable and the garbage collector reclaims it - analogous to closing a dormant bank account.
Generalisation
makeAccount could return multiple functions (e.g. withdraw, deposit, statement) that jointly manage shared private references. In OCaml, these would typically be packaged using records, though they are not covered in this course.