More about Lutz's new macro

Started by m i c h a e l, October 06, 2007, 10:58:28 AM

Previous topic - Next topic

newdep

#15
I hope this topic is not closed yet because it intresting ;-)

Especialy the addon from newBert, I liked the "light" intepretation.




QuoteAgain newLISP is not designed to be an OO language. A 'def-type' like macro works well for structuring data and packageing all functions related to that data type into one context. But its not original OO where data and methods are together in one object.


Will there be perhpas an internal change-addon to newlisp? Who knows.. ;-)
-- (define? (Cornflakes))

m i c h a e l

#16
I'm continuing to work through possible ways to model OO in newLISP. The PDFs on the Logo-based Elica that newBert posted links for (thanks, newBert!) have been fascinating. What Pavel describes in the papers is strikingly like newLISP's contexts. But once you begin to work with contexts as objects, the problem of not being able to nest contexts rears its ugly head. Or does it?



Since all newLISP contexts must be named with a symbol in the MAIN context only, I wonder if it would be helpful to think of objects in newLISP not like this:



http://www.kenrockwell.com/bmw/images/m3-2007/top-790.jpg">



But instead, like this:



http://www.kenrockwell.com/bmw/images/m3-2007/exploded-789.jpg">



Something to think about?



I've written some code that begins to duplicate the examples in Pavel's "http://www.elica.net/download/papers/ElicaLogoObjects.pdf">Elica Logo and Objects" paper. I wound up with something similar to the way m35's .new function (http://www.alh.net/newlisp/phpbb/viewtopic.php?p=8593">link) works, but by using a mixin called Class.


; C L A S S E S

(context 'Class)

(set '_next -1 'type Class)

(define (next) (sym (string (context) "-" (inc '_next)) MAIN))

(define (Class:new) (set 'obj (next)) (MAIN:new Class:type obj) (eval obj))

(define (Class:? obj) (= obj:type Class:type))

(context MAIN)


; P O I N T S

(set 'POINT:type POINT 'POINT:x 0 'POINT:y 0)

(new Class 'Point)

(set 'Point:type POINT)

(define (point x y) (set '_p (Point:new) '_p:x x '_p:y y '_p:self _p))

(set 'Point:zero (point 0 0))


; S E G M E N T S

(set 'SEGMENT:type SEGMENT 'SEGMENT:a Point:zero 'SEGMENT:b Point:zero)

(context 'Segment)

(set 'type SEGMENT)

(new Class)

(define (Segment:delete seg)
  (set 'pa seg:a 'pb seg:b)
  (and (MAIN:delete pa:self) (MAIN:delete pb:self) (MAIN:delete seg:self))
)

(context MAIN)

(define (segment ax ay bx by)
  (set '_s (Segment:new) '_s:a (point ax ay) '_s:b (point bx by) '_s:self _s)
)

(set 'Segment:zero (segment Point:zero Point:zero))


; T R I A N G L E S

(set
  'TRIANGLE:type TRIANGLE
  'TRIANGLE:ab Segment:zero
  'TRIANGLE:bc Segment:zero
  'TRIANGLE:ca Segment:zero
)

(context 'Triangle)

(set 'type TRIANGLE)

(new Class)

(define (Triangle:delete tri)
  (set 'ab tri:ab 'bc tri:bc 'ca tri:ca)
  (and
    (Segment:delete ab:self) (Segment:delete bc:self) (Segment:delete ca:self)
    (MAIN:delete tri:self)
  )
)

(context MAIN)

(define (triangle ax ay bx by cx cy)
  (set
    '_t (Triangle:new)
    '_t:ab (segment ax ay bx by)
    '_t:bc (segment bx by cx cy)
    '_t:ca (segment cx cy ax ay)
    '_t:self _t
  )
)

(set 'Triangle:zero (segment Point:zero Point:zero))

; S A M P L E R U N
; NOTE: The following code makes use of a user-defined function named 'bug'.
; 'bug' is not part of newLISP.

(bug (set 'pt (point 54 22)))
(bug pt:x pt:y pt:self (Point:? pt))

(bug (set 'sg (segment 23 54 65 34)))
(bug sg:a sg:b sg:self (Segment:? sg))

(bug (set 'pa sg:a))
(bug pa:x pa:y pa:self)

(bug (set 'pb sg:b))
(bug pb:x pb:y pb:self)

(bug (Segment:delete sg))
(bug sg:self pa:self pb:self)

(bug (set 'tr (triangle 11 22 45 23 65 34)))
(bug tr:ab tr:bc tr:ca (Triangle:? tr))

(bug (Triangle:delete tr))
(bug tr:self tr:ab tr:bc tr:ca)


This produces the following output:


-> (set 'pt (point 54 22)) = Point-5
-> pt:x = 54, pt:y = 22, pt:self = Point-5, (Point:? pt) = true
-> (set 'sg (segment 23 54 65 34)) = Segment-2
-> sg:a = Point-6, sg:b = Point-7, sg:self = Segment-2, (Segment:? sg) = true
-> (set 'pa sg:a) = Point-6
-> pa:x = 23, pa:y = 54, pa:self = Point-6
-> (set 'pb sg:b) = Point-7
-> pb:x = 65, pb:y = 34, pb:self = Point-7
-> (Segment:delete sg) = true
-> sg:self = nil, pa:self = nil, pb:self = nil
-> (set 'tr (triangle 11 22 45 23 65 34)) = Triangle-0
-> tr:ab = Segment-3, tr:bc = Segment-4, tr:ca = Segment-5, (Triangle:? tr) = true
-> (Triangle:delete tr) = true
-> tr:self = nil, tr:ab = nil, tr:bc = nil, tr:ca = nil


I've separated the contexts used to represent the objects (all uppercase) from the ones used as instance makers and method holders (title-case). I forget why I thought this was a good idea ;-)



The next thing is to model the interesting concept of rules (from the same http://www.elica.net/download/papers/ElicaLogoObjects.pdf">paper). That should be fun!



This is just one more experiment. One of many. But it solves the problem of making and deleting objects (contexts) without having to name them directly (semi-anonymous objects?). Any ideas for improvements or fixes?



m i c h a e l



P.S. If you're interested in the code for bug, let me know and I'll post it. But you have to promise to help bum it ;-)

m i c h a e l

#17
P.P.S. Sorry for the grotesquely large images lately. I'm linking directly to the original sites, so I can't change the image size directly. Is there a way to adjust the size within the image tag? I've tried using (I've excluded the <>s in the following, so it will show up):



img src="http://www.kenrockwell.com/bmw/images/m3-2007/top-790-big.jpg">http://www.kenrockwell.com/bmw/images/m ... 90-big.jpg">http://www.kenrockwell.com/bmw/images/m3-2007/top-790-big.jpg" alt="Whole Engine" width="640" height="480"  /



but this produces only:



<img>



Thanks for any help you can offer.



m i c h a e l

newBert

#18
Quote from: "m i c h a e l"I decided to dig up the http://www.angelfire.com/tx4/cus/shapes/index.html">link to a site that contains a number of object-oriented implementations of the classic shape example used in most OOP books.




Here is an example of mine. It is very simple but it shows the use of 'inheritance' and 'polymorphism' ... if I'm not mistaken, I'm not a specialist of OOP (but maybe of OOPS !)


#!/usr/bin/newlisp
;================================================
; Class & Objects with CONTEXT
; ----- newlisp 9.2.3 --------- oct. 2007 -----
;================================================

(context 'rectangle)
; class rectangle
(define (rectangle:rectangle (_width 30) (_height 15))
(set 'width _width)
(set 'height _height)
(set 'shape "Rectangle"))

(define (perimeter)
(string "(" width " + " height ") x 2 = " (mul (add width height) 2)))

(define (area)
(string width " x " height " = " (mul width height)))

(define (measure)
(println shape " " width "X" height " :")
(println "- surface area = " (area))
(println "- perimeter = " (perimeter) "n"))

(context MAIN)

(context 'square)
; class square
(new rectangle)  ; square is a special rectangle
(define (square:square (side 10))
(set 'width side)
(set 'height side)
(set 'shape "Square"))

(context MAIN)

;; main program

(new rectangle 'f1)
(f1 27 12)
(f1:measure)

(new square 'f2)
(f2 13)
(f2:measure)
   
;; fin du script
<r><I>>Bertrand<e></e></I> − <COLOR color=\"#808080\">><B>newLISP<e></e></B> v.10.7.6 64-bit <B>>on Linux<e></e></B> (<I>>Linux Mint 20.1<e></e></I>)<e></e></COLOR></r>

itistoday

#19
Hi, while playing around with Lutz's original macro I tried to do stuff like this:


(:x pt 2)

And it didn't work.  :p



So I set about to fix that.  I had planned on reading this thread when I was finished and low and behold I saw that michael had done a similar thing.  I then copied some of the suggestions made in this thread to make the code even nicer.  However, I'm still having problems, and forgive me but I only skimmed over this thread.



(BTW michael, here are smaller versions of those pictures, just remove the -big from the URL: http://www.kenrockwell.com/bmw/images/m3-2007/top-790.jpg">pic1, http://www.kenrockwell.com/bmw/images/m3-2007/exploded-789.jpg">pic2)



So here is my version as it is now:


(define-macro (data-type)
(let (ctx (context (args 0 0)))
    (set (default ctx) (expand '(fn () (cons ctx (args))) 'ctx))
    (dolist (item (rest (args 0)))
(set 'idx (+ $idx 1)
(sym item ctx)
(expand '(lambda-macro (_str _val)
(if (set '_val (eval _val))
          (nth-set ((eval _str) idx) _val)
          ((eval _str) idx)
)
)
'idx
)
)
)
ctx
)
)


However, (:x pt 5) still doesn't work!  It runs, it just doesn't modify pt. Oddly enough (point:x pt 5) does.  Can anyone help me out here as to why this is happening?



Also, how do I write a compound method like this:


(define-macro (point:move _pt _x _y)
(:x _pt _x)
(:y _pt _y)
)

; this doesn't work either

(define-macro (point:move _pt _x _y)
(point:x _pt _x)
(point:y _pt _y)
)

; if I try this:
(define-macro (point:move _pt _x _y)
(println (point:x _pt))
)

; I get this error:
invalid function : ((eval MAIN:_str) 1)


So that when I do (:move pt 5 6) [or (point:move pt 5 6)], point should contain the values 5 and 6.  Many thanks!
Get your Objective newLISP groove on.

m i c h a e l

#20
Quote from: "itistoday"(BTW michael, here are smaller versions of those pictures, just remove the -big from the URL: pic1, pic2)


Thank you! That looks much better.



m i c h a e l

itistoday

#21
OK, I haven't been able to figure out how to get it working using the previous paradigm, but I did fix it by changing the semantics a bit.



The data-type function is the same except the setter/getters are functions instead of macros:


(define-macro (data-type)
(let (ctx (context (args 0 0)))
    (set (default ctx) (expand '(fn () (cons ctx (args))) 'ctx))
    (dolist (item (rest (args 0)))
(set 'idx (+ $idx 1)
(sym item ctx)
(expand '(lambda (_str _val)
(if (set '_val (eval _val))
          (nth-set ((eval _str) idx) _val)
          ((eval _str) idx)
)
)
'idx
)
)
)
ctx
)
)


Next, forget about the macro-like syntax of (point:x pt 5).  Instead, quote the point:


(point:x 'pt 5)

That works.  Now I've even been able to get compound functions (not macros) to work:


(define (point:move _pt _x _y)
(point:x _pt _x)
(point:y _pt _y)
(eval _pt)
)

(point:move 'pt 8 7)


That works too.  And not only that, but using the colon syntax for getting works too! (but *not* setting)

Except you use the previous format of not quoting the object.


(:x pt)

If anyone figures out how to get this working using macros though... let me know.  It seems to me that newLISP macros have something funky going on with them besides simply changing their parameters to be quoted...
Get your Objective newLISP groove on.

itistoday

#22
OK, this is getting frustrating, I'm starting to get the impression that newLISP just isn't designed for object oriented programming (edit: which appears to be what Lutz said above, now that I'm reading through this thread in more detail...).  Using my previous code this does not work:


(set 'points '())
(dotimes (i 5)
(push (point i i) points)
)
(println (point:move '(points 0) 200 200))


I'm guessing you've probably gotta jump through some hoops by using temporary variables to get that to work...  Yeah, this works:


(set 'points '())
(dotimes (i 5)
(push (point i i) points)
)
(set 'tmp (points 0))
(println (point:move 'tmp 200 200))
(nth-set (points 0) tmp)


This is slightly disappointing... I'm hoping some newLISP guru will put my newbie-self in place and show me the proper way to do this...



Edit:  I think it's possible to actually get this to work by writing code to anticipate this situation in data-type.  For example it could check (list? _str) and if so then do the temporary variable thing itself.  Anyone wanna give this a shot?  I won't be able to work on this right now because I've got an another project, but once that's done if no one's done it I'll give it a shot and post here if I'm successful.
Get your Objective newLISP groove on.