sumsin <> writes:
> From 'Inside the C++ Object Model' by 'Stanley B. Lippman'
>
> 'The primary strength of the C++ Object Model is its space and runtime
> efficiency. Its primary drawback is the need to recompile unmodified
> code that makes use of an object of a class for which there has been
> an addition, removal, or modification of the nonstatic class data
> members.'
>
> Here I can understand the strength of C++ object model but can anybody
> elaborate the primary drawback of it.
Imagine you have:
class Widget

ublic Object {
private:
Rect bounds;
public:
virutal Rect& getBounds(void);
};
and a thousand of subclasses of Widget.
And suddenly, the user requets that the widgets may be oriented by
some angle on the screen. So you add a field:
class Widget

ublic Object {
private:
Rect bounds;
float angle;
public:
virutal Rect getBounds(void);
virutal float getAngle(void);
};
and lo, you have to recompile all the thousand of subclasses, because
now the field layout has changed, for all these classes.
Contrast that with CLOS:
> (defclass widget () ((bounds :initarg :bounds :accessor bounds)))
#1=#<STANDARD-CLASS WIDGET>
> (defclass button (widget) ((title :initarg :title :accessor title)))
#1=#<STANDARD-CLASS BUTTON>
> (defvar *button-1* (make-instance 'button :bounds #(10 20 110 40) :title "Test"))
*BUTTON-1*
> (inspect *button-1*)
#<COMMON-LISP-USER::BUTTON #x000334202008>: standard object
type: COMMON-LISP-USER::BUTTON
0 [BOUNDS]: #<ARRAY T (4) #x000334201F10>
1 [TITLE]: "Test"
INSPECT-- type :h for help; :q to return to the REPL ---> :q
We created the superclass and a subclass, and made an instance of the subclass.
Suddenly, we modify the superclass:
> (defclass widget () ((bounds :initarg :bounds :accessor bounds) (angle :initarg :angle :accessor angle :initform 0.0)))
WARNING: DEFCLASS: Class BUTTON (or one of its ancestors) is being redefined, instances are obsolete
#1=#<STANDARD-CLASS WIDGET :VERSION 1>
Of course new instances of the subclasses will take into account the
changes (nothing has to be done about the subclasses themselves):
> (defvar *button-2* (make-instance 'button :bounds #(10 20 110 40) :angle (/ pi 3) :title "At an angle"))
*BUTTON-2*
> (inspect *button-2*)
#<COMMON-LISP-USER::BUTTON #x00033426C9A0>: standard object
type: COMMON-LISP-USER::BUTTON
0 [BOUNDS]: #<ARRAY T (4) #x00033426C878>
1 [ANGLE]: 1.0471975511965977461L0
2 [TITLE]: "At an angle"
INSPECT-- type :h for help; :q to return to the REPL ---> :q
But what's more, the old instances of the subclasses have been updated too:
> (inspect *button-1*)
#<COMMON-LISP-USER::BUTTON #x000334202008>: standard object
type: COMMON-LISP-USER::BUTTON
0 [BOUNDS]: #<ARRAY T (4) #x000334201F10>
1 [ANGLE]: 0.0
2 [TITLE]: "Test"
INSPECT-- type :h for help; :q to return to the REPL ---> :q
>
In CLOS, it's even possible to define (and compile) subclasses before having defined the superclass:
> (defclass window (view) ())
#1=#<STANDARD-CLASS WINDOW :INCOMPLETE>
> (defclass view (widget) ())
#1=#<STANDARD-CLASS VIEW>
> (make-instance 'window :bounds #(0 0 512 342))
#<WINDOW #x0003342E24C0>
> (inspect *)
#<COMMON-LISP-USER::WINDOW #x0003342E24C0>: standard object
type: COMMON-LISP-USER::WINDOW
0 [BOUNDS]: #<ARRAY T (4) #x0003342E2400>
1 [ANGLE]: 0.0
INSPECT-- type :h for help; :q to return to the REPL ---> :q
>
--
__Pascal Bourguignon__