[solved] OOP

Started by incogn1to, March 05, 2011, 01:55:14 PM

Previous topic - Next topic

incogn1to

I found an interesting piece of code in scheme, but I failed to make it work in newLisp. Can anybody explain why?


(define (make-square side)
   (lambda (msg)
    (cond ((eq? msg 'area) (* side side))
      ((eq? msg 'perimeter) (* 4 side))
      (else (error "unknown message")))))

> (define s1 (make-square 4))
> (s1 'area)
> 16
Sibi imperare maximum imperum est

Sammo

#1
A direct translation of the Scheme code to newLisp might be:


; make-square
; 2011-03-05
; example
; (set 's1 (make-square 2))
; (s1 'area) ;result = 4
; (s1 'perimeter) ;result = 8
; (s1 'xxx) ;result = "unknown message" error
(define (make-square side)
(letex (s side)
(lambda (msg)
(cond
((= msg 'area) (mul s s))
((= msg 'perimeter) (mul 4 s))
(true (throw-error "unknown message")) ))))

but study the FOOP section of the newLisp manual for stronger object-oriented techniques.

-- Sam

m i c h a e l

#2
Hi incogn1to!



Even though they may look the same from the outside, newLISP and Scheme are very different languages. In the function make-square, for example, newLISP uses = instead of eq?. You would also need to change the else to true in the cond as well as error to throw-error.



What this Scheme code is doing is modeling object orientation using functional programming principles. You can do this same thing using FOOP:


> (new Class 'Square)
Square
> (define (Square:area) (* (self 1) (self 1)))
(lambda () (* (self 1) (self 1)))
> (define (Square:perimeter) (* 4 (self 1)))
(lambda () (* 4 (self 1)))
> (setq s1 (Square 4))
(Square 4)
> (:area s1)
16
> _


Objects are simply lists: the first element is its class; the rest are its attributes, which are accessed through their indexes. You can also define a named accessor to make the intention more apparent:


> (new Class 'Square)
Square
> (setq Square:side 1)
1
> (define (Square:area) (* (self Square:side) (self Square:side)))
(lambda () (* (self Square:side) (self Square:side)))
> (define (Square:perimeter) (* 4 (self Square:side)))
(lambda () (* 4 (self Square:side)))
> (setq s1 (Square 4))
(Square 4)
> (:area s1)
16
> _


Finally, you can simplify the code by defining the class within a context:


> (new Class 'Square)
Square
> (context Square)
Square
Square> (setq side 1)
1
Square> (define (area) (* (self side) (self side)))
(lambda () (* (self side) (self side)))
Square> (define (perimeter) (* 4 (self side)))
(lambda () (* 4 (self side)))
Square> (context MAIN)
MAIN
> (setq s1 (Square 4))
(Square 4)
> (:area s1)
16
>


m i c h a e l

incogn1to

#3
Thanks for the answers. I read about FOOP. Simply this lambda conception looked interesting for me.
Sibi imperare maximum imperum est

incogn1to

#4
Quote from: "Sammo"A direct translation of the Scheme code to newLisp might be:


; make-square
; 2011-03-05
; example
; (set 's1 (make-square 2))
; (s1 'area) ;result = 4
; (s1 'perimeter) ;result = 8
; (s1 'xxx) ;result = "unknown message" error
(define (make-square side)
(letex (s side)
(lambda (msg)
(cond
((= msg 'area) (mul s s))
((= msg 'perimeter) (mul 4 s))
(true (throw-error "unknown message")) ))))



Thanks for translation. Can you explain why we need letex in this case? Why lambda can't take side from function definition?
Sibi imperare maximum imperum est

Sammo

#5
QuoteCan you explain why we need letex in this case? Why lambda can't take side from function definition?

I am neither a Scheme nor newLisp expert, but I believe the significant difference between them (for this example) lies in a concept called http://www.c2.com/cgi/wiki?LexicalClosure">lexical closures.



When Scheme executes your make-square code, it creates (by way of the lambda expression) a closure in which the variable 'side' is bound to the value provided at execution time. When the resulting closure is then executed, the binding is reestablished and the expected result is produced.



newLisp doesn't implement closures (at least in the Scheme way), so we 'trick' it into forming a "hard closure" by rewriting the expression (i.e., substituting a fixed value for 'side') by way of the 'letex' function.



Without the 'letex' wrapper, newLisp produces a function (i.e., lambda expression) with references to the variable 'side.' With the wrapper, newLisp produces a function with the variable 'side' replaced with the value provided when the function was created.



Michael's FOOP example illustrates how closures can be implemented in newLisp.



-- Sam



Edit 2011-03-07: Removed an extraneous word.

Lutz

#6
well explained - more about this here:



http://www.newlisp.org/index.cgi?Closures">http://www.newlisp.org/index.cgi?Closures



linked from:



http://www.newlisp.org/index.cgi?Differences_to_Other_LISPs">http://www.newlisp.org/index.cgi?Differ ... ther_LISPs">http://www.newlisp.org/index.cgi?Differences_to_Other_LISPs

Ryon

#7
Small correction to Closures and Contexts page: "The function makes and adder function" s/b "The function makes an adder function"
\"Give me a Kaypro 64 and a dial tone, and I can do anything!\"

incogn1to

#8
Thanks for good answers.
Sibi imperare maximum imperum est