C++ is *not* the only OO language (was: Re: PHP objects and public/private methods)

Giorgos Keramidas keramida at ceid.upatras.gr
Wed Sep 5 02:50:23 EEST 2007


On 2007-09-05 01:11, Giorgos Keramidas <keramida at ceid.upatras.gr> wrote:
> Ένα CLOS class δεν έχει μόνο ένα superclass:

Κι ένα ακόμα παράδειγμα με 'function call chaining', που δείχνει ότι το
CLOS δεν υστερεί σε κάτι από το C++ inheritance μοντέλο.  Για την
ακρίβεια, αυτό είναι πιο κοντά στο μοντέλο της C++ επειδή το method name
που υλοποιείται από δύο _άσχετα_ μεταξύ τους superclasses έχει σε αυτή
την περίπτωση το _ίδιο_ όνομα.

Ορίζουμε πρώτα τα 3 γνωστά πλέον classes:

            shape                    streamable
              |                           |
              +-------------+-------------+
                            |
                         rectangle

|   CL-USER> (defclass shape ()
|              ((shape-name :initarg :shape-name
|                           :initform "A generic shape")))
|   #<STANDARD-CLASS SHAPE>
|   CL-USER> (defclass streamable ()
|              ((streamable-name :initarg :streamable-name
|                                :initform "A streamable object")))
|   #<STANDARD-CLASS STREAMABLE>
|   CL-USER> (defclass rectangle (shape streamable)
|              ((shape-name :initform "A rectangular shape")
|               (streamable-name :initform "A streamable rectangle")))
|   #<STANDARD-CLASS RECTANGLE>

Ορίζοντας ένα generic function με base-class το T (το "μαγικό"
superclass όλων των CLOS classes):

|   CL-USER> (defgeneric show (t))
|   #<STANDARD-GENERIC-FUNCTION SHOW (0)>

Τώρα επειδή είμαστε λίγο "περίεργοι", ορίζουμε ΠΡΩΤΑ ένα instance της
class `rectangle', παρόλο που ακόμα δεν έχουμε υλοποιήσει βασικά κανένα
specialization της `show' method:

|   CL-USER> (defparameter *keramida* (make-instance 'rectangle))
|   *KERAMIDA*

Μπορούμε ύστερα να ορίσουμε διαφορετικά method specializations,
τόσο για το `shape' class όσο και για το `streamable' class:

|   CL-USER> (defmethod show ((s shape))
|              (when (slot-boundp s 'shape-name)
|                (format t "~&~A" (slot-value s 'shape-name)))
|              (when (next-method-p)
|                (call-next-method)))
|   #<STANDARD-METHOD SHOW (SHAPE) {61BD9C79}>
|   CL-USER> (defmethod show ((s streamable))
|              (when (slot-boundp s 'streamable-name)
|                (format t "~&~A" (slot-value s 'streamable-name)))
|              (when (next-method-p)
|                (call-next-method)))
|   #<STANDARD-METHOD SHOW (STREAMABLE) {61CB9161}>

Και τα νέα μας method specializations παίζουν αυτομάτως:

|   CL-USER> (show *keramida*)
|   A rectangular shape
|   A streamable rectangle
|   NIL

Και τώρα πάμε να "επεκτείνουμε" κάπως το generic `show' function όλων
των αντικειμένων που έχουν ήδη φτιαχτεί και όλων όσα θα φτιαχθούν
αργότερα, στο μέλλον!

|   CL-USER> (defmethod show ((obj t))
|              (format nil "~&A ~A object" (class-of obj)))
|   STYLE-WARNING: redefining SHOW (#<BUILT-IN-CLASS T>) in DEFMETHOD
|   #<STANDARD-METHOD SHOW (T) {61FD1D19}>

Και αμέσως το generic function `show' ξέρει ότι αφού κάνει όλα τα άλλα
πράγματα που ξέρει να κάνει, επιστρέφει και το string που ορίσαμε στο
method implementation του T super-superclass:

|   CL-USER> (show *keramida*)
|   A rectangular shape
|   A streamable rectangle
|   "A #<STANDARD-CLASS RECTANGLE> object"
|   CL-USER>

το εντυπωσιακό εδώ είναι ότι αλλάξαμε σε _runtime_ την υλοποίηση μιας
superclass method, και φυσικά η Lisp χωρίς να ιδρώσει καν, συνέχισε
να κάνει αυτό που ξέρει ότι πρέπει να κάνει (αυτός ήταν και ο σκοπός
των `(when (next-method-p) (call-next-method))' calls στα σημεία που
μπήκαν άλλωστε).

Κι αυτή η νέα υλοποίηση της superclass method, προφανώς, ισχύει ακόμα
και για αντικείμενα που φτιάχνονται αργότερα:

|   CL-USER> (defparameter *v13* (make-instance 'rectangle))
|   *v13*
|   CL-USER> (show *v13*)
|   A rectangular shape
|   A streamable rectangle
|   "A #<STANDARD-CLASS RECTANGLE> object"
|   CL-USER>




More information about the Linux-greek-users mailing list