newlisp object system

Started by m35, March 29, 2007, 04:24:44 PM

Previous topic - Next topic

m35

I have been porting some code from Python to newlisp during the last few weeks. During this process I have recreated some of the Python libraries. I have also taken a good long look at how I want to mimic the object-oriented functionality of Python. This is what I came up with.



This function does most of the work when it creates a new instance.
;; Create a new instance of a class (i.e. context)
(define (.new ctx)
(local (new-instance class-counter instance-num _me)
; get the class counter
(set 'class-counter (sym "instance~count" ctx))
(unless (eval class-counter)
(set class-counter 0))
(set 'instance-num (inc class-counter))
; create the new instance
(set 'new-instance
(sym (string ctx "~instance~" instance-num) MAIN))
(new ctx new-instance)
(set 'new-instance (eval new-instance))
; add the self _me
(set 'new-instance:_me new-instance)
; call the (new) function if it exists
(if new-instance:new
; pass any args into the new function
(eval (append (list new-instance:new) (args))))
new-instance ; return
)
)
(constant (global '.new))




I can then use this simple object template when writing a class.
(context '__YOUR_CONTEXT_NAME_HERE__)
; Optional base class(es)
;(new __BASE_CLASS_HERE__) ; Base class


; Constructor and parameters -----------v
(define (__YOUR_CONTEXT_NAME_HERE__:new   )

; Your init code here
; e.g. (set 'instance-val "value")

)

(context 'MAIN)


Using this approach is very easy. e.g.
(load "StringIO.lsp")
(set 'memstream (.new StringIO))         => StringIO~instance~1
(memstream:write "Hello")                => 5
(memstream:seek 0)                       => 0
(memstream:read)                         => "Hello"


If I want an object to pass itself as a parameter (like self, Me, this, etc. in other languages), I use the _me field that was added when the object was created.
(some-function _me)

If I want to call a function in the parent class that was overloaded (overwritten) in a child class, I can do something like this
(context 'MyStringIOChild)
(new StringIO) ; Base class

(define (write str)
; Call the parent function
(local (parent.function)
(def-new 'StringIO:write 'parent.function)
(parent.function str)
)

(println "You wrote " str)
)

(context 'MAIN)


And with all this, I have a very simple and working object system that resembles the object system of many other languages.





There's just one problem I'm having: because contexts don't use ORO, all objects created must be manually deleted. If I don't delete them, I essentially have a memory leak.



I would love to have an object system that uses ORO. I made an attempt at it, where I would serialize objects using the (source) function. Whenever I wanted to interact with the object, I would deserialize it into a temporary context, perform the operations, then re-serialize it, and delete the context. Unfortunately my partial implementation of that approach was so terribly ugly that I couldn't bring myself to finish it.



Does anyone have any thoughts on creating a garbage-collected or ORO object system in newlisp?

cormullion

#1
I know nothing about this type of programming, but I found the following post from 2005:



http://www.alh.net/newlisp/phpbb/viewtopic.php?t=712">//http://www.alh.net/newlisp/phpbb/viewtopic.php?t=712



not looking that helpful though

Lutz

#2
Objects have to be deleted manually, because they are bound to context symbols and cannot exist anonymously. A context object is always referenced by its symbol never by an anoymous memory pointer. In order to delete the object its symbol has to be set to nil.



Objects represented by namespaces serve best for a template-like object system without classes and using 'def-new' fo mixins of single functions. If you are looking for classic class-object systems, then newLISP is just not the right language.



newLISP's namespace object are best suited for bigger non-volatile objects like programming modules to partition bigger programs or smaller objects when thy are not too volatile (don't have to be deleted frquently).



Still, your implementation is smart and well usable for programming tasks where it is reasonable to delete objects manually.



Lutz

Dmi

#3
Hmmm... Jus for fun :-)



I realize that if we'll use a naming convention to make "anonymous" objects (for ex. like: anon-1234), then we can write a function to enumerate all symbols in all contexts, to collect all their values which starts with "anon-*"

after that we can safely delete thoose which are not in the collected list anymore.



;-)
WBR, Dmi

Jeff

#4
That sounds suspiciously like a mark and sweep :)
Jeff

=====

Old programmers don\'t die. They just parse on...



http://artfulcode.net\">Artful code