wilson@carcoar.Stanford.EDU (Paul Wilson) (09/09/89)
[This is a slightly revised version of something I posted, but which looks from here like it never got out to the net. Sorry for any redundancy. -- PRW] It seems to me that types are abstracted *roles* that objects can play. The same set of messages may mean a different thing in one role than in another, so sets of messages really don't capture this intuition. For example in my role as a computer scientist, if somebody asks me "what do you do?" I respond in one way, but in my role as a boardsailer, I respond in another. So at a conference, I may say "garbage collection and reconstructive memory," but at the beach I say "I fall down a lot." Similarly, when an object is of more than one type, you get collisions between messages understood by one type and same-named messages understood by another. For example, suppose a window object responds to a "size" message by returning a point object giving its screen dimensions in pixels; suppose also that a queue object responds by returning an integer saying how many things are in the queue. What happens when an object is both a queue and a window (say, because it's a queue that can represent its contents to the user)? It seems to me that the "right," intuitive way to do this, in a strongly typed system, is to resolve this by the role the object is playing. If the window system has a pointer to it *as a window*, it should respond as a window. And if a simulation object has a pointer to it *as a queue*, it should respond as a queue. Does anybody do types this way? It seems to me the most natural way to do things: if an object is of multiple types, it has multiple interfaces -- different "languages" it can speak. And different languages may have the same words, but with different meanings. That's okay, as long as the object knows what language it's being spoken to in. This leads to a more refined notion of type safety -- not only should an object "understand" all messages that could be sent to it at runtime (in the sense of having a method defined for that message), but it should understand it _in_the_right_way_. It should be speaking the "same language" as the message sender. In summary: A type should be a role with an associated protocol. That's different from a set of messages, since two different protocols could use exactly the same message selectors and mean entirely different things. So it's more abstract that syntactically matching messages to method names. It's also different from a class, because it's *not* a statement about implementation. Different objects of (subtypes of) the same type do "the same thing" in response to the same messages, even if they do it "in different ways," as determined by their implementations. And a class is a particular implementation that implements one or more types. Note that all of these things have identities rather than just properties; even types should be testable for identity as well as the strucural equivalence implied by accepting a particular set of messages. On this view, types end up being capabilities to which access can be restricted via scoping or maybe (if they're first class) by controlling who they're handed to. One object might be allowed to see another object as "an underling I can order around," while yet another is only allowed to see it as "a peer I can't talk to that way." Now it's not clear to me that making all these distinctions, but it seems like the kind of explicitness static-typing fans would like. Any comments? Whose wheels am I reinventing? :-) -- Paul Paul R. Wilson Software Systems Laboratory lab ph.: (312) 996-9216 U. of Illin. at C. EECS Dept. (M/C 154) wilson@bert.eecs.edu Box 4348 Chicago,IL 60680 Paul R. Wilson Software Systems Laboratory lab ph.: (312) 996-9216 U. of Illin. at C. EECS Dept. (M/C 154) wilson@carcoar.stanford.edu Box 4348 Chicago,IL 60680