Path: utzoo!attcan!uunet!lll-winken!lll-tis!ames!pasteur!ucbvax!decwrl!purdue!i.cc.purdue.edu!j.cc.purdue.edu!pur-ee!uiucdcs!uiucdcsm!grogers From: grogers@uiucdcsm.cs.uiuc.edu Newsgroups: comp.lang.c++ Subject: Re: oo definition request Message-ID: <4800024@uiucdcsm> Date: 18 May 88 22:50:00 GMT References: <4800021@uiucdcsm> Lines: 111 Nf-ID: #R:uiucdcsm:4800021:uiucdcsm:4800024:000:4732 Nf-From: uiucdcsm.cs.uiuc.edu!grogers May 18 17:50:00 1988 This is not short but here goes. [And please don't comment on my notation, I'm just making it up as I go along.] It seems to me that the key requirement for object-oriented programming is that a program must always present the illusion that an object's state can only be changed by the object itself and the object does so in response to messages it receives from other objects. Given this requirement it is possible to write in an oo style within a non-oo language (pascal). However, it is also possible to cheat. An oo language enforces the style and does not allow cheating. This is similar to structured programming through careful use of gotos or through enforced use of if-then-else, for, while.... I disagree with the Wegner definition, since the object's state can be manipulated independently of the object. (e.g. obj->state = newvalue). The problem with this is that the object does not know that it has changed and cannot notify any other objects that may be interested in that change nor can it perform value validity checking. (e.g. A text object should be redisplayed if it changes or an array index should not be out of bounds.) You might say that the "=" is not assignment but a message that is sent to the object. Fine, but then the program does not have direct access to the object's state and that's not what Wegner said. One aspect of oo programming that complicates things is the question of whether classes should be first class objects. If so, their instance variables and methods can change (both value and existence) during the execution of the program. Now we cannot allow direct access to the instance variables of an object because these may not exist at some point in the program lifetime. An example: Class C { instance vars: a, b, c; class vars: x, y, z; methods: ... } aC isa Class newInstance; aC.a = 5; C removeInstanceVar "a"; aC.a = 6; The last statement must fail because the instance variable no longer exists. This can only be done by late binding. I admit that this example is somewhat far fetched, but I can also imagine of creating or destroying a method for writing an object to disk. If the write method does not exist, the object is for read only use. Next issue: inheritance. The major advantage of inheritance is improved code reuse. I contend that in the absence of classes as first class objects inheritance only provides code reuse. The function of the class could be replicated in each of the subclasses and the subclass would not behave differently (of course, there must still be only one set of class instance variables). I'm not advocating this, since unless it's completely automatic the superclass copies will diverge as the subclasses are modified. Inheritance also provides a good mechanism for deriving abstract data types. "Subclass A is just like its superclass B except for ...." Unfortunately, sometimes the subclass is more general and sometimes more specific. Although this is necessary it can be confusing. With inheritance, only the "except fors" need be stated. Without, class A must explicitly define a method, say X, and explicitly pass control flow, "A.X: y { self B.X: y }" [the notation is: receiverObject Class.Method: params] for each method it wants to inherit. It seems to me that an interesting question is: what's the difference between abstract data type programming and object oriented programming? I would say that the primary difference is polymorphism. Historically speaking, adts have been implemented as hidden data areas with access functions. Thus, each data type has a set of specific functions for accessing the adt's data. For example: stack_insert( s, item) and queue_insert( q, item). While oo programming assumes polymorphism as implemented through message passing. So here we have: s insert: item and q insert: item. It is the object that determines which "insert" method is executed rather than the invoker. This has a major impact on the code that is written. In an adt language we would have switch (type_of X) case sphere: sphere_render( X, PHONG ); case nurb: nurb_render( X, PHONG ); ... all other cases... an oo language would have the switch implicit in the method lookup and so we just need X render: PHONG While I do think that inheritance and memory management are very useful and should be part of any programming environment, I don't think they are necessary for oo programming. So, what do you think? Greg Rogers University of Illinois at Urbana-Champaign Department of Computer Science 1304 W. Springfield Ave. Urbana, IL 61801 (217) 333-6174 UUCP: {pur-ee,convex,inhp4}!uiucdcs!grogers ARPA: grogers@a.cs.uiuc.edu CSNET: grogers%uiuc@csnet-relay