newLISP Fan Club

Forum => newLISP newS => Topic started by: Lutz on December 06, 2009, 06:46:14 AM

Title: Mutable objects in FOOP in development v.10.1.8
Post by: Lutz on December 06, 2009, 06:46:14 AM
Mutable objects in FOOP in development v.10.1.8



Mutable objects in FOOP (Functional Object Oriented Programming) has been the most asked feature for FOOP, and now its here:


(new Class 'Circle)

(define (Circle:move dx dy)
    (inc (self 1) dx)
    (inc (self 2) dy))

(set 'aCircle (Circle 1 2 3))

(:move aCircle 10 20)

aCircle => (Circle 11 22 3)


Now FOOP methods drop the object parameter and the target objects is accessed via the new function 'self'.



For files and complete changes notes see:



http://www.newlisp.org/downloads/development/



See changed FOOP documentation here:



http://www.newlisp.org/downloads/development/newlisp_manual.html#foop

http://www.newlisp.org/downloads/development/newlisp_manual.html#colon

http://www.newlisp.org/downloads/development/newlisp_manual.html#self
Title: Re: Mutable objects in FOOP in development v.10.1.8
Post by: itistoday on December 06, 2009, 10:04:30 AM
This is fascinating, and I can't help but think that we both should have communicated regarding what we were doing.



Since our email exchange I've created an object-oriented system for newLISP that I'll announce today, it has several advantages over FOOP, even this redesigned version. In short it allows you to do real object-oriented programming with reference passing, and is backwards compatible with many old versions of newLISP. :-)



I.e., it solves this problem with FOOP (which exists even with this updated version):


(setf my-obj (MyFOOPClass 1 2 3))

(define (func-1 obj)
(func-2 obj)
)

(define (func-2 obj)
(:modify obj 54)
obj
)

(func-1 obj)

obj ; obj remains unchanged here


But this is still a very welcome change to FOOP, as I'm assuming the use of the 'self' function makes it more efficient too!
Title: Re: Mutable objects in FOOP in development v.10.1.8
Post by: Lutz on December 06, 2009, 10:34:43 AM
When you wrap a destructive function (:move ...) with a non-destructive one (func-1 and func-2), then of course the result is non-destructive. But 'obj' will be modified after excecution of (:modify ...). One must stay in the paradigm of either FOOP or normal .



Yes, the new 'self' makes FOOP also faster, less overhead internally and less newLISP code to write. Before when modifying objects, you always had to return the modified object and then do a re-assignment on the higher level, which now is not necessary anymore.
Title: Re: Mutable objects in FOOP in development v.10.1.8
Post by: itistoday on December 06, 2009, 10:39:59 AM
Quote from: "Lutz"When you wrap a destructive function (:move ...) with a non-destructive one (func-1 and func-2), then of course the result is non-destructive. But 'obj' will be modified after excecution of (:modify ...). One must stay in the paradigm of either FOOP or normal.


Sure, I'm just saying that this still doesn't allow full-on object-oriented programming (which is something that I need for that database wrapper, but thankfully I found an excellent solution).



Note to Dragonfly users: don't upgrade to this yet, as Dragonfly makes use of the old-style FOOP.



Edit]
Title: Re: Mutable objects in FOOP in development v.10.1.8
Post by: itistoday on December 06, 2009, 10:53:22 AM
When used in this way, Functional-OOP becomes a misnomer. ;-p
Title: Re: Mutable objects in FOOP in development v.10.1.8
Post by: m i c h a e l on December 06, 2009, 11:53:18 AM
I've wondered about this ever since I first toyed around with mutability in my experiments (BTW, bravo on self, Lutz! Perfectly simple and fits newLISP to a tee.). Surely, if the 'F' in FOOP means anything, it must be immutable objects, right? I don't know. I've tried to approach FOOP without preconceptions or prejudices. Still, I've tried hard to find a good way to add mutability to FOOP. Unchangeable objects would appear to be an oxymoron. When I think of objects, I think of little self-manipulating packages of data.



If FOOP is to lose its 'F', perhaps it should be called newOOP instead ;-)



m i c h a e l
Title: Re: Mutable objects in FOOP in development v.10.1.8
Post by: TedWalther on December 06, 2009, 12:50:27 PM
Cool.  It looks like "self" is doing what I was hoping for with "this".  I'll go refresh myself on FOOP again.  Things are calming down at work again; perhaps over Christmas break I can power through and fix up configure-alt enough to be a suitable replacement for configure, and get a first release of the OpenBSD port/package done.  Are there any outstanding issues with configure-alt, Lutz?  Also, the OpenBSD test environment is now upgraded to version 4.6.
Title: Re: Mutable objects in FOOP in development v.10.1.8
Post by: Lutz on December 07, 2009, 05:03:49 AM
The fact that each object in FOOP is the functional expression which generates itself - its own constructor expression - still justifies the 'F' in FOOP.


(new 'Class 'Obj)
(Obj 1 2 3) ;=> (Obj 1 2 3)
(eval (Obj 1 2 3)) ;=> (Obj 1 2 3)
(apply (first (Obj 1 2 3)) (rest (Obj 1 2 3))) ;=> (Obj 1 2 3)


The same is true for nested objects, they are nested constructor functions:


(new Class 'Foo)
(new Class 'Bar)
(set 'x 1 'y 2 'z 3)
(Foo (Bar x y z) (Bar x y z)) ;=> (Foo (Bar 1 2 3) (Bar 1 2 3))
(Foo (Bar 1 2 3) (Bar 1 2 3)) ;=> (Foo (Bar 1 2 3) (Bar 1 2 3))


So the object-oriented programming in FOOP may not be full functional, but the object is. Not functional object-oriented programming but functional-object oriented programming.





ps -> Ted: I don't think there are any outstanding issues in configure-alt at the moment.
Title: Re: Mutable objects in FOOP in development v.10.1.8
Post by: TedWalther on December 07, 2009, 11:02:18 AM
How is (new) different from (copy)?  Is object an internal datatype the way contexts and red-black dictionaries are?
Title: Re: Mutable objects in FOOP in development v.10.1.8
Post by: cormullion on December 07, 2009, 02:24:53 PM
This looks cool, but ... Can you explain why in your code


(define (Circle:move dx dy)
    (inc (self 1) dx)
    (inc (self 2) dy))

(set 'aCircle (Circle 1 2 3))

(:move aCircle 10 20)

aCircle => (Circle 11 22 3)


you  pass three numbers with Circle, yet only the first two are modified, and yet they're referred to as (self 1) and (self 2), so these aren't indexes? But:


QuoteOld FOOP methods have to be rewritten to drop the obj parameter:



    old : (define (Foo:method obj p1 p2) ...)

    new : (define (Foo:method p1 p2) ...)


looks like I'd want to modify 0 and 1, not 1 and 2.



As I said, confused a bit here... :)
Title: Re: Mutable objects in FOOP in development v.10.1.8
Post by: Lutz on December 07, 2009, 05:21:57 PM
It is less confusing if we describe the code in original object oriented terminology (all in italic font). The following function call is called a message call in OO:


(:move aCircle 10 20)

:move is the message sent to the object aCircle and 10 and 20 are the message parameters, only two of them in this example. In OO Java or JavaScript you would write aCircle.move(10, 20).



The object aCircle encapsulates the object data and the methods how to process the data. So when we receive the call, we really are inside the object aCircle and can refer to it with (self). There are only two parameters in the :move message, in this case 10 and 20 for the dx and dy method parameters.



The function (self) returns the object with the Class Id at index 0 and values for x-position, y-position and radius at index 1,2 and 3. In out example (self) is aCircle, the receiver of the message


(define (Circle:move dx dy)
    (inc (self 1) dx)
    (inc (self 2) dy))


Because all the shapes of Class Circle use the same methods, we don't have to carry them around in each object instance of that Class, but can just point to with a Class Id, which is the first thing in the aCircle object  (Circle 1 2 3).



Note that :move is not the same thing as Circle:move. :move is the message sent, and Circle:move is the method processing the message  received by the object aCircle which is an instantiation of Class Circle. The message :move is polymorph and depending on the object Class it may point to different methods, there could also be a Rectangle:move method or Triangle:move method.
Title: Re: Mutable objects in FOOP in development v.10.1.8
Post by: m i c h a e l on December 07, 2009, 06:26:51 PM
I started this response before Lutz answered you, cormullion, but I'll post it anyway :-)



I think Circle's third attribute is its radius, which, of course, would not be affected by moving the circle.



The indexes used in self represent the positions of the attributes within an object. The first element of an object is the class (at index 0). In the case of Circle, x is 1, y is 2, and the radius is 3.



Most object-oriented languages don't specifically declare an argument for the object passed to a method (Python being one exception). They use some form of pseudo-variable, usually self or this, that can only be used within a method (you'll notice calling newLISP's self outside of a method will always return nil).



Just remember that self refers to the object that received the message, not the arguments of the method.



m i c h a e l
Title: Re: Mutable objects in FOOP in development v.10.1.8
Post by: TedWalther on December 07, 2009, 06:32:05 PM
Thanks, I've been wanting to use context-objects more extensively, with millions of items of the same class type, but wasn't sure how to do it without duplicating the methods for every single object instance.  It looks like there is a way after all, even if I don't fully grokk it yet.  Hurray!  I won't get out of memory errors after all.
Title: Re: Mutable objects in FOOP in development v.10.1.8
Post by: Lutz on December 08, 2009, 09:48:02 AM
There was a newlisp-10.1.8-foop.tgz in the development directory, whoever downloaded this, throw it away, it is an older version. The correct version containing the FOOP changes talked about in this thread is: newlisp-10.1.8.tgz.
Title: Re: Mutable objects in FOOP in development v.10.1.8
Post by: cormullion on December 08, 2009, 10:25:10 AM
Ah. Great - I wasn't thinking straight... Thanks both.



Mostly I use FOOP mainly in timeutilities.lsp at the moment. I've converted it over to the new style and it seems to work fine.



One thing you could advise on: I have a method called :shift which adds time to a time object. In the old style FOOP I was happy enough with the clarity and restriction of immutability - it made sense for 'fixed' times (if not for appointments):


>; older style FOOP
(set 'xmas (Time 2009 12 25))
(Time 1261699200 0)
> (set 'boxing-day (:shift xmas 1 'days))
(Time 1261785600 0)
> (:represent xmas)
"Friday December 25 2009 00:00:00"
> (:represent boxing-day)
"Saturday December 26 2009 00:00:00"


With the new style, doing this also shifts xmas day - objects being no longer immutable. So I tried putting in a flag at the end of the :shift method call such that you could say either 'please modify the object' or not. So, with f as the increment, the shift method ends like this:


(if modify-flag
      (begin
         (setf (self 1) (add f (self 1)))
         (self)) ; return the modified original object
      (begin
         (set 'new-time (self))
         (setf (new-time 1) (add f (new-time 1)))
         new-time ; return the modified copy
))))


Is this the best way to do this? It appears to work, but...
Title: Re: Mutable objects in FOOP in development v.10.1.8
Post by: m35 on December 08, 2009, 11:51:50 AM
Wow Lutz--you've been a big proponent of the functional/immutable approach for so long, I'm surprised and impressed you added mutable objects. I hope you don't feel like you're compromising on all us poor, industry brainwashed, OOP developers ;)
Title: Re: Mutable objects in FOOP in development v.10.1.8
Post by: Lutz on December 08, 2009, 03:46:36 PM
... actually, I think OO programming is a good paradigm. I just didn't want to put something into the language which didn't fit well. Now, built only with the colon operator :, the 'self' function and namespaces, FOOP has a good feel to it, is small and naturally fits into newLISP.
Title: Re: Mutable objects in FOOP in development v.10.1.8
Post by: m i c h a e l on December 09, 2009, 09:17:42 AM
Quote from: "cormullion"Is this the best way to do this? It appears to work, but...


How about turning the problem around by leaving the method as is and simply copying the original?


> (setq xmas (Time 2009 12 25))
(Time 1261699200 0)
> (setq boxing-day (:shift (copy xmas) 1 'days))
(Time 1261785600 0)
> (:represent xmas)
"Friday December 25 2009 00:00:00"
> (:represent boxing-day)
"Saturday December 26 2009 00:00:00"
> _


copy creates a new object from its argument, and it's this new object that will be referenced by self within the method. As long as your method returns the modified object (as you were already doing), you can use it either way.



m i c h a e l
Title: Re: Mutable objects in FOOP in development v.10.1.8
Post by: cormullion on December 09, 2009, 11:15:09 AM
Thanks - that's probably the best solution...