OOP and inheritance

Started by newBert, November 26, 2007, 10:19:08 AM

Previous topic - Next topic

newBert

In chapter 17 of the NewLISP Manual (Object-Oriented Programming in newLISP) polymorphism is described clearly and simply. That shows how NewLISP can adapt easily to apparently complex things...



I studied, with my poor knowledge and competence in computer science, the notion of inheritance and here is a little script which attempts to illustrate the question.



Please, would you critically examine it so as to let me know wether I've well understood the concept.

#!/usr/bin/newlisp

(context 'rectangle)
; Class 'rectangle' with a constructor method
(define (rectangle:rectangle (width 30) (height 15))
(set 'w width)
(set 'h height)
(set 'nam "rectangle"))

(define (perimeter)
(string "(" w " + " h ") x 2 = " (mul (add w h) 2)))

(define (area)
(string w " x " h " = " (mul w h)))

(define (measure)
(println "A " nam " of " w " by " h)
(println "has a surface area of " (area) ",")
(println "and a perimeter of " (perimeter) ".n"))

(context MAIN)

(context 'square)
; Class 'square' inherits from 'rectangle'
(new rectangle)
; Constructor of 'square'
(define (square:square (side 10))
(set 'w side)
(set 'h side)
(set 'nam "square"))

(context MAIN)

; main program
(new rectangle 'fig1)
(fig1 27 12)
(fig1:measure)

(new square 'fig2)
(fig2 13)
(fig2:measure)


I think there is also a little polymorphism. I don't use the colon operator there... yet it would be better, sorry.

;)
<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>

cormullion

#1
Very good - clear and direct!



I wondered whether the first (context MAIN) was needed. But in fact I think it demonstrates that (context 'square) isn't part of context rectangle although  it inherits from it, neither is it a nested context (which don't exist...). So leaving it in is good!

newBert

#2
Quote from: "cormullion"Very good - clear and direct!



I wondered whether the first (context MAIN) was needed. But in fact I think it demonstrates that (context 'square) isn't part of context rectangle although  it inherits from it, neither is it a nested context (which don't exist...). So leaving it in is good!

Yes, it was both intentional and conditioning by a distant practice of Basic or Basic-like language (with its 'block' ... 'end block', etc.).



I think it's just a little more readable. And I would like to modify those definitions in a very NewLISP way, using lists and colon operator as described in the User Manual (chapter 17)... to compare clearness and efficiency.

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

m i c h a e l

#3
Hi newBert!



Inheritance can be used in a number of ways. The one most commonly discussed is the "is a" type of inheritance (the one used in your code), which models a classification relationship between objects. Mixins and implementation inheritance are two other types.



Your code uses the earlier context-based way of doing OOP, which was found to have weaknesses. The way I would do that now is:


;; a rectangle constructor:
(define (rectangle:rectangle (width 30) (height 15)) (list rectangle width height))

;; a method defined using let to get the rectangle's width and height:
(define (rectangle:perimeter r)
   (let  (w (r 1) h (r 2)) (string "(" w " + " h ") x 2 = " (mul (add w h) 2)))
)

;; a method defined using straight indexing:
(define (rectangle:area r) (string (r 1) " x " (r 2) " = " (mul (add (r 1) (r 2)))))

;; a method defined using rectangle's area and perimeter methods:
(define (rectangle:measure r)
   (println "A " (r 0) " of " (r 1) " by " (r 2))
   (println "has a surface area of " (:area r) ", ")
   (println "and a perimeter of " (:perimeter r) ".n")
)

;; a square is a rectangle
(new rectangle 'square)

;; a square constructor
(define (square:square (side 10)) (list square side side))

;; main program
(set 'fig1 (rectangle 27 12))
(:measure fig1)

(set 'fig2 (square 13))
(:measure fig2)


Programming this way takes a little getting used to, but once you do, it starts to feel a lot more nimble than heavier OOP frameworks (I never did grok Ocaml's object system).



m i c h a e l



P.S. I think Lutz mentioned somewhere on the club that (context MAIN) should be used before beginning a new context. Sorry for not looking it up.

Fanda

#4
I could never abandon my version of OOP, so I wrote a new version:

http://www.intricatevisions.com/source/newlisp/oop.lsp">http://www.intricatevisions.com/source/newlisp/oop.lsp



And using it:
(load "oop.lsp")

(set 'Rectangle
  (object ()
    width 30 height 15
    nam "rectangle"

    init (fn ((w 30) (h 15)) (set 'width w 'height h))
    perimeter (fn () (string "(" width " + " height ") x 2 = " (mul (add width height) 2)))
    area (fn () (string width " x " height " = " (mul width height)))
    measure (fn ()
     (println "A " nam " of " width " by " height)
     (println "has a surface area of " (area) ",")
     (println "and a perimeter of " (perimeter) ".n"))
))

(set 'Square
  (object (Rectangle)
    nam "square"
    init (fn ((side 10)) (set 'width side 'height side))
))

;; main program
(set 'fig1 (obj-init Rectangle 27 12))
(obj-do 'fig1 (measure))

(set 'fig2 (obj-init Square 13))
(obj-do 'fig2 (measure))


I like it because it is compact and has a different feel to it.



Fanda

newBert

#5
Quote from: "m i c h a e l"Hi newBert!

Your code uses the earlier context-based way of doing OOP, which was found to have weaknesses.

I was aware of the weakness of my code. It was an adaptation of what I learnt about OOP through Python first. I like your version which is closer to the "newLISP spirit" than mine (which is perhaps just a little educational),


Quote from: "Fanda"I could never abandon my version of OOP ( ... )

I like it because it is compact and has a different feel to it.

and I like Fanda's version too, which is closer to OOP standard (so to speak), maybe a little clearer (particularly for a beginner), as we can see in language like Python, Rebol and probably others that I don't know ...



I'm going to study both ways trying to avoid dissipating my efforts.



In any case, thank you for your very interesting replies.
<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>

newdep

#6
Fanda's ways is better because its indeed for the beginner more readable..



perhpas the newlisp manual needs this extention ->




Quote
;; The object initiation

;; is done by pre-defining the object-class.



 (define object-class:object-class)



;; Now the object initiation with an object-class

;; defined in a list because that is OOP.

;; object-class is a context symbol!



 (set 'object '(object-class "attribute and methods go here"))



;; A class function



 (define (object-class:pick x) (x 1))



;; A polymorphism



 (:pick object)


-- (define? (Cornflakes))

m i c h a e l

#7
There's no doubt in my mind I would have preferred Fanda's way of doing OOP when I first came to newLISP. I've struggled with many different ways of doing objects in this language (maybe six so far), but this latest way feels the most native to newLISP. An important part of this is that the objects are used functionally (without mutable state). Without this, it's not FOOP.



We are free to use any frameworks we wish in newLISP, including Fanda's. The problem with frameworks is they must be included (and maintained). So far, I've managed to get by without a framework.



So use whatever makes you happy (that's why we code in newLISP, isn't it?). As for me, I'll keep exploring FOOP, wherever it may lead :-)



m i c h a e l



P.S. I'm still working on the FOOP introduction and hope to have it finished soon!

Lutz

#8
here: http://newlisp.org/index.cgi?page=newLISP-FOOP">http://newlisp.org/index.cgi?page=newLISP-FOOP I have put together a page  how FOOP came about and what makes it peculiar for newLISP.



Lutz

newdep

#9
Quote from: "Lutz"here: http://newlisp.org/index.cgi?page=newLISP-FOOP">http://newlisp.org/index.cgi?page=newLISP-FOOP I have put together a page  how FOOP came about and what makes it peculiar for newLISP.



Lutz


Very clear and good paper Lutz!

and a special thanks to Micheal for his work!

(Micheals examples are a real mind mixer sometimes ..this is a compliment!..;-)



FOOP it is ;-)
-- (define? (Cornflakes))

newBert

#10
Quote from: "m i c h a e l"
We are free to use any frameworks we wish in newLISP, including Fanda's. The problem with frameworks is they must be included (and maintained). So far, I've managed to get by without a framework.

Yes I agree. This was a dilemna for me before...


Quote from: "Lutz"here: http://newlisp.org/index.cgi?page=newLISP-FOOP">http://newlisp.org/index.cgi?page=newLISP-FOOP I have put together a page  how FOOP came about and what makes it peculiar for newLISP.

...but Lutz's paper finishes convincing me there is a real NewLISP way (and modern way) of doing OOP.



Nevertheless Fanda's work is an interesting and concrete demonstration of what NewLISP is able to do and as far as it can go ...



I'm only a humble and occasional NewLISP user. I'm admiring before all your work. I take a lot of things but  I'm incapable of returning so much with my modest contribution.



Thanks
<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>