;; FinancialHistory 

(class FinancialHistory Object
	(cashOnHand incomes expenditures) 
	(method setInitialBalance: (amount) 
		(begin 
			(set cashOnHand amount) 
			(set incomes    (new Dictionary))
			(set expenditures (new Dictionary))
			self))
	(method receive:from: (amount source) 
		(begin
			(at:put: incomes source (+ (totalReceivedFrom: self source) amount))
			(set cashOnHand (+ cashOnHand amount))))
	(method spend:for: (amount reason) 
		(begin 
			(at:put: expenditures reason (+ (totalSpentFor: self reason) amount))
			(set cashOnHand (- cashOnHand amount))))
	(method cashOnHand () cashOnHand)
	(method totalReceivedFrom: (source) 
		(if (includesKey: incomes source) 
			[(at: incomes source)] 
			[0]))
	(method totalSpentFor: (reason) 
		(if (includesKey: expenditures reason)
		    [(at: expenditures reason)]
		    [0]))
	(classMethod initialBalance: (amount)
		(setInitialBalance: (new self) amount)))



;; Using financial history 
(val myaccount (initialBalance: FinancialHistory 1000))
(spend:for: myaccount 50 #insurance)
(receive:from: myaccount 200 #salary)
(spend:for: myaccount 100 #books)
(totalSpentFor: myaccount #books)
(spend:for: myaccount 50 #books)
(totalSpentFor: myaccount #books)


;; methods define how an instant of FinancialHistory 
;; responds to different messages 
;; class methods defines how the class itself responds to a message 
;; Everything is an object so the class FinancialHistory is also an object 
;; Sending the initialBalance: message to the class object tells it 
;; to create a new instance of FinancialHistory with the specified balance. 

;; relationship between objects and classes 


FinancialHistory 
(new FinancialHistory)
(isKindOf: FinancialHistory Class) 
(isKindOf: (new FinancialHistory) Class) 
(isKindOf: FinancialHistory Object) 
(isKindOf: (new FinancialHistory) Object) 



;; Inheritance way to resuse/extend exising code 

;; DeductibleHistory responds to all messages 
;; defined in FinancialHistory can choose 
;; to "over-ride" the response. 
;; Inherits all the instance variables 
;; Notice the use of: self, super 

(class DeductibleHistory FinancialHistory 
	(deductible) 
	(classMethod initialBalance: (amount) 
	     (initDeductibleHistory (initialBalance: super amount)))
	(method initDeductibleHistory () 
	     (begin 
		(set deductible 0)
  		self))
	(method spend:deduct: (amount reason)
	     (begin 
		(spend:for: self amount reason)
		(set deductible (+ deductible amount))))
	(method spend:for:deduct: (amount reason deduction)
	     (begin
		(spend:for: self amount reason) 
		(set deductible (+ deductible deduction))))
	(method totalDeductions () deductible))



;; Using deductible history 

(val myaccount (initialBalance: DeductibleHistory 1000))
(spend:for: myacount 50 #insurance) 
(receive:from: myaccount 200 #salary) 
(cashOnHand myaccount) 

(totalDeductions myaccount) 
(spend:deduct: myaccount 100 #mortgage)
(cashOnHand myaccount) 
(totalDeductions myaccount) 
(spend:for:deduct: myaccount 100 #3-martini-lunch 50)
(cashOnHand myaccount) 
(totalDeductions myaccount) 


;; Classes are objects 
;; Sidenote: reflection - language can manipulate it's own 
;; objects - powerful but difficult to understand 

(protocol FinancialHistory) 




;; Name of variables are resolved statically (just by staring at the code) 
;; Name of message is resolved dynamically (i.e we can't tell until a 
;; message is sent what method will be invoked to respond to it. 

;; IMPORTANT: Information hiding: only a method invoked on an object 
has direct access to the instance variables of that object 
;; (i.e all instance variables are private) 



;; Message send and inheritance 
;; method search always begins in the class of the receiver (except super) 


(class C Object () 
	(method m1 () (m2 self))
	(method m2 () #C))

(class D C()
	(method m2 () #D))



;; Core of smalltalk is probably one of the simplest languages 
;; All the power comes from the initial basis (the "pre-defined" objects) 


;; Blocks, continuation-passing style 

(val index 0) 
[(set index (+ index 1))]

;; Block is an object similar to a lambda-expression in Scheme 
;; which is evaluated not by applying it, but by sending it the 
;; value message 

(val incrementBlock [(set index (+ index 1))])
(val sumBlock [(+ sum (* index index))])

(val sum 0) 
(set sum (value sumBlock))
(value incrementBlock)
(set sum (value sumBlock))


;; Blocks are used to implement conditional expressions
;; IMPORTANT: MESSAGE PASSING IS THE ONLY CONTROL STRUCTURE 


(if (< sum 0) [#negative] [#positive])


(if (< sum 0) #negative #positive)



;; For those interested in operational semantics 
;; check out page 393 of your book 
;; As we discussed the main control structure 
;; is message send and as you can see from 
;; the SENDUSER rule it's relatively complicated
;; It's a good exercise to try to understand 
;; how this rule works 




