Mutable FOOP

Started by m i c h a e l, June 03, 2009, 12:01:46 PM

Previous topic - Next topic

m i c h a e l

Dear Club,



My continuing adventures in FOOP have led me to a new discovery: mutable FOOP objects.



By adding a self-reference to its second element, a mutable object can preserve its state without manually resetting the reference each time the object is updated. (Actually, manual resetting still occurs, but it's hidden within the object's methods.)



Preliminary disclaimer: Please remember this code is still experimental and unproven. Proceed with care. You can view (and the brave can download) the code http://www.neglook.com/code/mutable-objects.lsp">here.



First, let me introduce a class method and three object methods that can be included in your "init.lsp" file in case you do a lot of FOOP programming (or you could put it in a file called "foop.lsp" that you load before doing serious FOOP):


;; [class method] generic class predicate
(define (Class:? it) (= (and it (list? it) (it 0)) (context)))

;; making objects displayable
(define (Class:string  it) (MAIN:string it))
(define (Class:print   it) (MAIN:print (:string it)))
(define (Class:println it) (:print it) (MAIN:print "n"))


The class method :? is not essential for this demonstration, but it is included for completeness.



I've had these methods defined in my "init.lsp" for a long time now without any problems, but everyone's setup is different, so beware!



Next is the code for doing mutable objects:


(new Class 'Mutable)

;; note: mutable objects require accessors to update their state
;; an inherited helper method called :access simplifies accessor writing

;; the constructor creates the object's reference
(define (Mutable:Mutable id)
(set id (cons (context) (cons id (args))))
)

;; an accessor for the object's id (currently read-only)
(define (Mutable:id it) (it 1))

;; a helper method for writing accessors
(define (Mutable:access it idx value allow-nil?)
(setq this (eval (:id it)))
(if (or value allow-nil?)
(begin
(setf (this idx) value)
(set (:id it) this)
)
(this idx)
)
)


Next, an example Mutable class:


(new Mutable 'Point)

;; keeping a reference to the inherited constructor so we can overwrite it
(setq Point:^Point Point:Point)

;; overwriting the constructor
(define (Point:Point id (x 0) (y 0))
(Point:^Point id x y)
)

;; Point's x and y accessors using inherited :access method
(define (Point:x it value) (:access it 2 value))
(define (Point:y it value) (:access it 3 value))

;; Point's string representation
(define (Point:string it) (replace "MAIN:" (string it) ""))

;; moving a Point to a specific place (x y)
(define (Point:move it x y) (:x it x) (:y it y))

;; sliding a Point by some amount (x y)
(define (Point:slide it x y)
(:move it (MAIN:+ (:x it) x) (MAIN:+ (:y it) y))
)

;; adding two Points together
(define (Point:+ it other)
(:slide it (:x other) (:y other))
)


Finally, the code to produce a sample run:


;; a helper function that displays an expression and its result
;; as if it had been entered on the command-line
 (define (run e)
(print "> " (string e) "n")
(:println (eval e))
)

(println "Sample Run using Mutable Points")
(run '(Point 'p1 10 20))
(run 'p1)
(run '(:slide p1 5 8))
(run 'p1)
(run '(Point 'p2 88 99))
(run '(:+ p1 p2))
(run 'p1)
(run 'p2)
(println "> _")


Which produces the following output:


Sample Run using Mutable Points
> (Point 'p1 10 20)
(Point p1 10 20)
> p1
(Point p1 10 20)
> (: slide p1 5 8)
(Point p1 15 28)
> p1
(Point p1 15 28)
> (Point 'p2 88 99)
(Point p2 88 99)
> (: + p1 p2)
(Point p1 103 127)
> p1
(Point p1 103 127)
> p2
(Point p2 88 99)
> _


Before settling on symbols in the MAIN context for the references, I used a Tree named obj with string references. While this solution was adequate, it lacked the natural feel the symbols provide.



That's it! Mutable objects. Looking forward to hearing how they work for you!



m i c h a e l

newdep

#1
you know micheal, first of all I always write your name wrong dont know why that is.. and secondly every time you post these wonderful solutions I always

need to read it 2 or 3 times befor i get it.. Also this one.. I need to realy think

befor I get it .. thats actualy a compliment on how you bind your code !



Give me 3 more readings ill be back with a reply ;-)
-- (define? (Cornflakes))

m i c h a e l

#2
Quote from: "newdep"you know micheal, first of all I always write your name wrong dont know why that is.


Norman, that's meta! But maybe I'm only saying that because I've got http://www.metaness.org">metaness on the brain ;-)


Quote from: "newdep"and secondly every time you post these wonderful solutions I always need to read it 2 or 3 times befor i get it.


Elegant solutions always come from a chaos of construction.


Quote from: "newdep"Also this one.. I need to realy think befor I get it ..


The circularity of it is probably confusing. The reference part, I mean. We have a symbol in an object that is referencing that object, and all of the methods use that symbol to update that object.


Quote from: "newdep"thats actualy a compliment on how you bind your code !


Thank you, Norman :-)


Quote from: "newdep"Give me 3 more readings ill be back with a reply ;-)


Sounds good!



m i c h a e l

cormullion

#3
Ah, this looks interesting. I seem to remember my brain didn't immediately take to the immutability aspect of foop, so this may persuade some more of my brain cells to go foop.



And you seem to have gone all Gödel Escher Bach on us, Michael... ?

m i c h a e l

#4
cormullion,



Weren't you working on something to do with GS that needed mutable objects? Maybe this solution can help you achieve that. It really just moves the resetting of the variable into the accessors, but if there ever was a good reason for accessors, this is it.



I'm glad my Gödel/Escher/Bach correspondence courses are starting to pay off ;-)

cormullion

#5
At the time I was wondering how to integrate FOOP with newLISP-GUI... Ie, an object to represent state and behaviour, then instances of it created and displayed on a canvas or layout. For example, an object that describes how an analog meter works, then placed as instances so that they could show different levels. I was having trouble getting started. (I then got sidetracked into using Phun (http://www.phunland.com/wiki/Home">//http://www.phunland.com/wiki/Home) which was a bit easier... :)


QuoteI'm glad my Gödel/Escher/Bach correspondence courses are starting to pay off ;-)


Ah, you got yours!? Unfortunately, the postman didn't deliver any of the course materials to my house, since I had enrolled under the name "Return T. O. Sender"...

m i c h a e l

#6
Quote from: "cormullion"At the time I was wondering how to integrate FOOP with newLISP-GUI... Ie, an object to represent state and behaviour, then instances of it created and displayed on a canvas or layout. For example, an object that describes how an analog meter works, then placed as instances so that they could show different levels. I was having trouble getting started.


Ah yes, I see. I, too, was hoping custom widgets and widget groupings would be possible with FOOP, but the mutability issue did hamper it. I've got myself spread a bit thin at the moment, so I wonder if I'll ever get around to it. Plus, FOOP is still young yet, which is why I always refer to it as an experiment.


Quote from: "cormullion"since I had enrolled under the name "Return T. O. Sender"...


So, the jig is up! cormullion is actually Return of Return T.O. Sender fame! Wow, I've been talking with the Return all this time. I'm gonna go tell all my friends. Bye!



m i c h a e l



P.S. Thanks for the link to Phun. Looks like fun.