[solved] OOP

Q&A's, tips, howto's
Locked
incogn1to
Posts: 8
Joined: Sat Mar 05, 2011 9:51 pm
Location: Riga, Latvia
Contact:

[solved] OOP

Post by incogn1to »

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

Code: Select all

(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
Last edited by incogn1to on Sun Mar 06, 2011 7:17 pm, edited 1 time in total.
Sibi imperare maximum imperum est

Sammo
Posts: 180
Joined: Sat Dec 06, 2003 6:11 pm
Location: Loveland, Colorado USA

Re: Objects

Post by Sammo »

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

Code: Select all

;	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
Posts: 394
Joined: Wed Apr 26, 2006 3:37 am
Location: Oregon, USA
Contact:

Re: Objects

Post by m i c h a e l »

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:

Code: Select all

> (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:

Code: Select all

> (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:

Code: Select all

> (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
Posts: 8
Joined: Sat Mar 05, 2011 9:51 pm
Location: Riga, Latvia
Contact:

Re: Objects

Post by incogn1to »

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

incogn1to
Posts: 8
Joined: Sat Mar 05, 2011 9:51 pm
Location: Riga, Latvia
Contact:

Re: Objects

Post by incogn1to »

Sammo wrote:A direct translation of the Scheme code to newLisp might be:

Code: Select all

;	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
Posts: 180
Joined: Sat Dec 06, 2003 6:11 pm
Location: Loveland, Colorado USA

Re: Objects

Post by Sammo »

Can 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 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.
Last edited by Sammo on Mon Mar 07, 2011 1:53 pm, edited 1 time in total.

Lutz
Posts: 5289
Joined: Thu Sep 26, 2002 4:45 pm
Location: Pasadena, California
Contact:

Re: Objects

Post by Lutz »


Ryon
Posts: 248
Joined: Thu Sep 26, 2002 12:57 am

Re: Objects

Post by Ryon »

Small correction to Closures and Contexts page: "The function makes and adder function" s/b "The function makes an adder function"

incogn1to
Posts: 8
Joined: Sat Mar 05, 2011 9:51 pm
Location: Riga, Latvia
Contact:

Re: Objects

Post by incogn1to »

Thanks for good answers.
Sibi imperare maximum imperum est

Locked