(* Lecture: References, Closures and Objects *) (* ------------------------------------------------ *) (* Mimicking object-oriented programming *) local val counter = ref 0 in fun tick () = (counter := !counter + 1; !counter) fun reset() = (counter := 0) end (* This declaration introduces two functions {\tt{tick:unit -> int}} and {\tt{reset:unit -> unit}}. Their definitions share a private variable {\tt{counter}} that is bound to a reference cell containing the current value of a shared counter. The {\tt{tick}} operation increments the counter and returns its new value, and the {\tt{reset}} operation resets its value to zero. The types already suggest that implicit state is involved. *) (* Suppose we wish to have several different instances of a counter and different pairs of functions tick and reset. We can achieve this by defining a counter generator *) (* newCounter: unit -> {tick : unit -> int, reset: (unit -> unit)} *) fun newCounter () = let val counter = ref 0 fun tick () = (counter := !counter + 1; !counter) fun reset() = (counter := 0) in {tick = tick, reset = reset} end (* We've packaged the two operations into a record containing two functions that share private state. There is an obvious analogy with class-based object-oriented programming. The function {\tt{newCounter}} may be thought of as a {\em{constructor}} for a class of counter {\em{objects}}. Each object has a private instance variable {\tt{counter}} that is shared between the methods {\tt{tick}} and {\tt{reset}}. Here is how to use counters. *) val c1 = newCounter(); val c2 = newCounter(); #tick c1 (); (* 1 *) #tick c1 (); (* 2 *) #tick c2 (); (* 1 *) #reset c1 (); #tick c1 (); (* 1 *) #tick c2 (); (* 2 *) (* Notice, that c1 and c2 are distinct counters! *)