Help with some basic object-oriented programming

Started by cormullion, April 16, 2006, 08:52:49 AM

Previous topic - Next topic

cormullion

I thought I ought to learn a bit of "object-oriented" programming. Following the examples in the book, with some changes, I thought about something like this:


(context 'Account)
(define (make-new nme bal ph)
(println nme " "  bal " " ph)
(set 'ctxt (replace " " (upper-case nme) ""))
(new Account 'ctxt)
(set 'ctxt (eval ctxt))
(set 'ctxt:full-name nme 'ctxt:balance bal 'ctxt:phone ph))

(define (Account:deposit amount)
(inc 'balance amount)
(println full-name "'s new balance is " balance))

(define (Account:withdraw amount)
(dec 'balance amount)
(println full-name "'s new balance is " balance))

(define (Account:statement)
(println "Fullname: " full-name)
(println "Balance: " balance))

(context 'MAIN)

(Account:make-new "John Doe" 123.45 "555-555-1212")


The idea is to create a context automatically from the name. But at the moment it fails on (new Account) with "symbol not in MAIN context in function new : ctxt

called from user defined function Account:make-new

".



What's the problem?



And then, having successfully created dozens of these accounts, how do I iterate across them?

Lutz

#1
Here are the changes to make it work and comments after the important lines:

(context 'Account)
   (define (make-new nme bal ph)
      (println nme " "  bal " " ph)
      (set 'ctxt (replace " " (upper-case nme) ""))
      (set 'ctxt (sym ctxt MAIN)) ; MAIN is context MAIN, don't need to quote it
      (new Account ctxt)  ; new takes a symbol as second argument
      (set 'ctxt (eval ctxt)) ; unwrap the context inside the symbol in ctxt
      (set 'ctxt:full-name nme 'ctxt:balance bal 'ctxt:phone ph)
      ctxt)  ; return the new context to work with
 ......

(context MAIN) ; don't need to quote cuase MAIN contains MAIN (but doesn't harm)


Note that the function returns the new conetxt JOHNDOE, so you can do this:



> (set 'customer (Account:make-new "John Doe" 123.45 "555-555-1212"))
John Doe 123.45 555-555-1212
JOHNDOE
> (customer:deposit 200)
John Doe's new balance is 323.45
323.45
> JOHNDOE:balance
323.45
>


Lutz

cormullion

#2
Thanks Lutz!



Now, having got this working, how do I find all the new objects that I've created using Account:new. Say I want to list everyone's balance.  Do I store them myself or can I ask newLISP for all Account objects?[/quote]

Lutz

#3
Yoy would keep a list yourself, i.e. you could push all accounts on a list during creation:



> (push (Account:make-new "John Doe" 123.45) TheAccounts)
John Doe 123.45 nil
JOHNDOE
> (push (Account:make-new "Mary Jane" 456.78) TheAccounts)
Mary Jane 456.78 nil
MARYJANE
> TheAccounts
(MARYJANE JOHNDOE)
> (map (fn (acc) (println acc:balance)) TheAccounts)
456.78
123.45
(456.78 123.45)
>


The last list you see: (456.78 123.45), is the result of the 'map' statement, because the return value of the 'println' statement is the balance printed



Lutz

cormullion

#4
OK, I think I get it. So, given a string, I can turn it into a symbol that should be a context name (continuing this example):


(set 'c (replace " " (upper-case "John Doe") ""))


then how do I get the balance?


(set 'c (replace " " (upper-case "John Doe") ""))
(println c "'s balance is" ...)


I'm finding this a little tricky. Does everyone else find it really easy? :-)

Lutz

#5

(set 'c (replace " " (upper-case "John Doe") ""))

> (set 'customer (eval (sym c MAIN)))
JOHNDOE
> customer:balance
123.45
>


It gets complicated when handling objects with their string instead of their contexts. Because now everytime you have to create the symbol from the name and then get the context.



Once an object is created you should handle it with its context not the name string.


Quote
I'm finding this a little tricky. Does everyone else find it really easy? :-)


Many would agree with you. There are two things to comment on this:



(1) handling contexts and symbols requires good knowledge of evaluation rules in newLISP. I.e. understanding the difference between a context and a symbol or the fact that contexts evaluate to themselves, that symbols can refer to contexts, i.e: (set 'foo aContext) etc.



(2) newLISP is primarily not an object oriented language. OO programming is possible using contexts (name spaces) but if you are into heavy OO programming then newLISP is not the right language to use. newLISP's preferred data structure is the list, and a list can also hold methods (functions).



Lutz

cormullion

#6
Thanks. I'm more or less with you now. The confusing part is this, I think:


(set 'ctxt (sym ctxt MAIN))  
(new Account ctxt)  
(set 'ctxt (eval ctxt))


It looks like a roundabout approach. But I can see (dimly) the logic behind it...

Lutz

#7
The confusion comes from the fact, that 'new' and 'context' take a symbol, while in terms like (print ctx:var) the 'ctx' either is the context or contains one.



Let me expand on your example:

(set 'ctxt "Hello")  ; ctxt contains a string
(set 'ctxt (sym ctxt MAIN))  ; we made the symbol Hello
; above statement is the same as saying:
(set 'ctxt 'Hello) ; put the symbol Hello into ctxt
(new Account ctxt) ; new takes a symbol in target (set '(ctxt (eval ctxt)) ; peel the context out of the symbol


The symbol Hello now contains the context Hello.



Lutz