From mboxrd@z Thu Jan 1 00:00:00 1970 X-Spam-Checker-Version: SpamAssassin 3.4.4 (2020-01-24) on polar.synack.me X-Spam-Level: X-Spam-Status: No, score=-1.9 required=5.0 tests=BAYES_00 autolearn=ham autolearn_force=no version=3.4.4 X-Google-Language: ENGLISH,ASCII-7-bit X-Google-Thread: 103376,82c7a4dae672250f X-Google-Attributes: gid103376,public From: John G. Volan Subject: "Object" types vs. "Value" types Date: 1996/03/20 Message-ID: <4inn6f$1at@dayuc.dayton.saic.com> X-Deja-AN: 143345781 distribution: world references: content-type: text/plain; charset=ISO-8859-1 x-xxmessage-id: organization: Science Applications International Corp. (SAIC) mime-version: 1.0 newsgroups: comp.lang.ada Date: 1996-03-20T00:00:00+00:00 List-Id: In article <4ih2pv$pku@dmsoproto.ida.org> David Wheeler, wheeler@aphrodite.csed.ida.org writes: >Michel Gauthier (gauthier@unilim.fr) wrote: ... >: Stacks are designed to organise values, not objects. >: Stacks are objects, not values. > >Not true. This stack organizes Items. Items might be values, or they might >be references. There is no reason to assume they must be one or the other. >For performance reasons you might choose to stack references instead of >the actual values, but there's no reason they MUST be one or the other. ... >: David probably means either stacks of (item=>references to stacks) or >: stacks of >: (item=> some implementation of the stack abstract type with an initial algebra >: behaviour). >: The latter actual type is an academic feature that has strictly no >: practical use. > >Disagree; see my example of arrays of arrays. ... In his book _Object Oriented Analysis and Design With Applications_, Grady Booch defines an "object" as something which has "state", "behavior, and "identity." Booch defines "state" as: The state of an object encompasses all of the (usually static) properties of the object plus the current (usually dynamic) values of each of these properties. Booch quotes Khoshafian and Copeland's definition of "identity": Identity is that property of an object which distinguishes it from all other objects. The identity of an object is something ineffably linked with that object, and with that object alone. Even if two objects are both in exactly the same state, they are still distinct objects, because their identities are different. On the flip side, the identity of an object is that property which never changes, regardless of all the changes of state that it experiences. In light of these notions, I long ago came to the conclusion that, as far as programming was concerned, there was a useful distinction to be made between two sorts of data types: "object" types and "value" types. An "object" type is a data type for which the distinction between "identity" and "state" was strong, whereas a "value" type would lack this strong distinction. A "value" can be duplicated in many different locations, and each instance of that "value" would be considered "identical" to all the others. No matter where you saw it, it would be the "same value". An "object", on the other hand, can occupy only one location, and cannot be "duplicated" elsewhere, not as such. You might be able to duplicate the _state_ of an object into another location, but then you wouldn't conclude that you then had the "same object" at that new location. Rather, you would conclude that there was a _different_ object at that location, and now that object happened to have the "same state" as your original object. At least, for the moment -- the state of an object can change. Yet even when that happens, the object doesn't suddenly become a "different object." It always remains the "same object." It just goes into different states at different times. Those different states might change its behavior, but it still remains "itself." Conversely, "values," as such, do not have states that can change. In a certain Platonic-ideal sense, a "value" is something eternal and unchanging. Now, understand what I mean by this: Let's say for instance that you see the number 2 at a particular location at a particular time, and then later see a different number, say 3, at that location. The value _at_ that location changed, but in no way did "the number 2" change. The number 2 is still the integer value that follows 1 and precedes 3 -- always has been and always will be. And the behavior of "the number 2" never changes, either: If you add one to the number 2, you'll always get the number 3, and if you subtract one from it, you'll always get the number 1. Always, forever and ever, world without end, amen. :-) What does all this philosophizing have to do with Ada? Well, IMHO, this distinction between "objects" and "values" maps quite neatly to the Ada concept of limited versus non-limited types. In my view, if you're going to categorize something as an "object", and invest it with all the connotations implied by that designation, then by rights the type ought to be limited. Assignment just doesn't make sense for an "object" type. You shouldn't be able to just "copy" an object willy-nilly -- what would that mean? Oh, you could copy the _state_ of that object into another object (write yourself a Copy procedure). Or you could copy the _identity_ ('Access) of that object from one (access) variable to another (access) variable. But copy the "object" per se? No, I'd rather shut off assignment rather than open up that can of worms. Physical objects in the real world don't go around being indiscriminately replicated (Star Trek's replicators are still just a fantasy), so I'd prefer the "objects" in my software to share the same kind of "solidity." On the other hand, if you do have a data abstraction for which assignment makes sense, that's okay too, you can make it non-limited -- I just wouldn't call that an "object" type, I'd call it a "value" type. Note that there's nothing about this notion of "value" types that precludes such "object-oriented" concepts as "inheritance" and "polymorphism" and "type extension" and "dynamic dispatching." I think it's perfectly reasonable to talk about having classes of "value" types, with derived value types inheriting attributes and behavior from ancestor value types, and adding new attributes and behavior, and so forth. "Value" classes can work just like "object" classes -- the only difference is that assignment is defined for the former but shut off for the latter. (Indeed, it's my humble (and perhaps radical) opinion that the very term "object-oriented" is a misnomer. The paradigm that everybody is so gung-ho about these days should have been called "*CLASS*-oriented" programming. A programming language could hypothetically give you _objects_ without necessarily giving you _classes_ as well. It's the _classes_, and the relationships between them, that give you all that juicy inheritance and polymorphism.) There's also nothing in this "value" concept that precludes the use of unbounded dynamic data structures or structural sharing. All of that is just private implementation details anyway. The bottom line is that if you want assignment to be meaningful for your data abstraction, then the publicly-visible semantics of your abstraction have to be totally stripped of any notion of unique identity. If you use assignment to duplicate a particular "value" to numerous locations, every single instance of that "value" must behave exactly like every other instance, without any "identifiable" distinction between them. If you assign a "different value" into one of those locations, this should not affect the behavior of the original value manifested at any of the other locations. Moreover, if you do any other kind of operation with a side effect that changes the "value" in one particular variable, none of the other variables still holding the old value should behave any differently, even if secretly all those variables were sharing a data structure. Whatever machinations you have to engage in behind the scenes in order to achieve these effects doesn't matter, as long as the semantics of "value" types is maintained as far as clients are concerned. Contrast this with a limited "object" type: You won't be able to use assignment to copy an "object" to multiple locations, although you might make multiple copies of an _access value_ that "identifies" that object. However, if then you perform an operation through one of these pointers that changes the state of the designated object, then the same change of state will automatically be observed through all of the other pointers designating that same object. Now, as for a particular abstract data type, such as our moldy old friend, the stack: Is a stack an "object"? Or is it a "value"? "Object"? "Value"? "OBJECT"? "VALUE"? WELL, IS IT ONE OR THE OTHER?!?!?!?!?!?!?!?!? My answer is: FOR GOODNESS SAKES, YES!!!!!!!!!!! :-) :-) :-) It can be _either_, depending on how you choose to perceive it. I believe most folks would tend to view a stack as an "object" (and that's how I tend to view it myself), on the grounds that the Push and Pop operations are thought of as having "side-effects." However, I admit that one might reasonably argue for a view that interprets a stack as a "value," by analogy with another "aggregate" abstraction: the array. Array types in Ada are non-limited, so you can do assignment on them. If two arrays happen to hold the same sequence of element values, then they're considered to have the same "array value." By analogy, one might say that two stacks that contain the same sequence of stacked element values should be considered as the same "stack value." My philosophy: Pick whichever semantic scheme best fits your application, implement it, and be happy. Just call it by the right name. :-) I even reflect that philosophy in my chosen naming style: I tend to let the package name carry the sense of an abstraction, and I use some "nondescript" identifier for the type encapsulated in the package, on the grounds that everybody should refer to it as "Package.Type" anyway. Well, "Object" is the nondescript identifier I will pick, if and only if the type is limited. "Value" is the nondescript identifier I'll pick, if and only if the type is non-limited. So, for example, if a stack is an "object", I'll have: generic type Item is private; package Stack is type Object is limited private; ... end Stack; Otherwise, if a stack is just a "value", I'll have: generic type Item is private; package Stack is type Value is private; ... end Stack; ------------------------------------------------------------------------ Internet.Usenet.Put_Signature ( Name => "John G. Volan", E_Mail => "John_Volan@dayton.saic.com", Favorite_Slogan => "Ada95: The *FIRST* International-Standard OOPL", Humorous_Disclaimer => "These opinions are undefined by SAIC, so" & "any use would be erroneous ... or is that a bounded error now?" ); ------------------------------------------------------------------------