Path: utzoo!attcan!uunet!mcsun!ukc!edcastle!dcl-cs!aber-cs!athene!pcg From: pcg@cs.aber.ac.uk (Piercarlo Grandi) Newsgroups: comp.object Subject: Re: The Emperor Strikes Back Message-ID: Date: 28 Feb 91 21:42:44 GMT References: <3351@sequent.cs.qmw.ac.uk> <1991Feb26.191336.1947@m.cs.uiuc.edu> Sender: pcg@aber-cs.UUCP Organization: Coleg Prifysgol Cymru Lines: 138 Nntp-Posting-Host: odin In-reply-to: johnson@cs.uiuc.EDU's message of 26 Feb 91 19:13:36 GMT On 26 Feb 91 19:13:36 GMT, johnson@cs.uiuc.EDU (Ralph Johnson) said: johnson> While closures can be used to implement objects, it is not the johnson> principal style. The principal style is that an argument is a johnson> record with one field pointing to an array of procedures, and johnson> that procedure calling is always done by indirection through johnson> this array. This is how C++ and Smalltalk do it, if you are johnson> willing to think of a Smalltalk class as an array johnson> of procedures. No, that is *not* how C++ and Smalltalk do it. We are speaking of completely different things here. Scoping and overloading are compeltely different issues. In your picture the object *is* a closure, because methods of a class are lexically closed with respect to its fields, to the point that the relevant offsets are hardcoded in the function implementations (shallow binding implementation of lexical scoping), in both C++ and Smalltalk. The pointer to the array of procedures is merely one row of the 2D associative table that the overload resolver code needs to match function interfaces with value types and get the relevant function implementations, and has nothing to do with whether that is a closure or not, and indeed is not part of the object at all. That pointer is just a type code. Some less constraining OO implementations use an arbitrary number as type code and use hashing to do function interface/value type resolution. Smalltalk/Actor oriented people, being locked in this particular implementation of the overload resolver, are blinkered and cannot see that what they call "dynamic binding" is really dynamic overload (on just the first argument!) resolution and has nothing to do with scoping, and is not an essential aspect of the system, while scoping is essential to keep together the attributes of a class (for traditional class based OO systems, e.g. not CLOS). This view also makes them (has made be them in the past, but I repented and was saved!) blind to the possibility of overload resolution based on multiple arguments, and arbitrary mix and match of interfaces and implementations, and creates a lot of non problems centered around artificious things like "inheritance". This has at times crazy consequences; for example in C++ static overloading is resolved on all the arguments to a method, but virtuals (dynamic overloading) are overloaded only with respect to the first argument, an arbitrary restriction. johnson> Further, I believe that dynamic binding is essential to johnson> object-oriented programming, and hereby declare any programming johnson> language without it to be not object-oriented. Is the converse also true? That is, if you have dynamic binding the language *is* OO? johnson> One of the main ideas of an object is that its user does not johnson> have to know anything about how to implement operations upon johnson> it, that the object is in complete control. Different objects johnson> will have the same sets of operations but implement them johnson> differently. This applies also to languages that do not support directly the OO decomposition paradigm, I am afraid. ML for example. I actually see things very differently. I see the original OO/capability function interface/value type matrix, and at each element a function implementation, and OO programming being about clustering this matrix in the type dimension(s), not in the interface one, because it is presumed that implementations operating on the same type(s) are more strongly related than implementations with the same interface, and thus a decomposition paradigm that clusters them together results in better modularation and thus reuse than other decomposition paradigms in most cases. Whether "interface/type(s) -> implementation" resolution is dynamic or static or how the matrix is implemented are totally immaterial issues in this view. I represent that OO programming is accurately described by it. johnson> Any one of these objects can be replaced by any other. This is johnson> essential for the development of groups of components that can johnson> be mixed and matched with each other. Even more essential would be algebras that allow more flexible mix and match than is traditionally possible in most OO languages, like one interface with multiple implementations, or viceversa, and arbitrary algebras on interface and implementations definitions (something that some people call inheritance) or overloading based on multiple types (a ninterface/type matrix with more than 2 dimensions). These are not encompassed by your definition of OO, but IMNHO they are all part of the OO decomposition paradigm, as above. johnson> In short, if C++ did not have virtual functions, it would not johnson> be object-oriented. Here we disagree completely. You make OO depend on one linguistic feature. I make it depend on support for particular style of decomposition. I tend to think this is more poignant, unless you can show that the one linguistic feature is *essential* in supporting OO decomposition paradigm, which cannot be done, because there are large OO applications that do not need it. Would you dare go as far as saying that a program written in C++ or Simula 67 in which virtual is never required and used *cannot be* called an OO program, even if it it written according to the OO decomposition paradigm? I would then be able to say that Smalltalk is not OO because it does not support directly multiple inheritance (or arbitrary mix and match of interfaces and implementations) or overloading on more than one argument (general clustering of operations in the type dimension(s) of the matrix). These are all things that are in general useful, even if they are not necessary for large and significant applications. You can still build OO programs, that is those built according to the OO decomposition paradigm, even if you don't have dynamic overloading, just as if you don't have multiple overloading, just as if you don't have arbitrary mix and match of interfaces or implementations, just as if you don't have full latent types. If each of these is missing you cannot tackle some class of OO applications, but the lack of any or all of these does not mean that you are not doing OO programming. Naturally an argument can be made that dynamic overloading, while not being an essential component of the OO decomposition paradigm, makes using this paradigm much more natural on a possibly large class of applications (those where some degree of type latency is required). The same can be said of multiple inheritance, multiple argument overloading, and arbitary mix and match of interfaces and functions, of course. -- Piercarlo Grandi | ARPA: pcg%uk.ac.aber.cs@nsfnet-relay.ac.uk Dept of CS, UCW Aberystwyth | UUCP: ...!mcsun!ukc!aber-cs!pcg Penglais, Aberystwyth SY23 3BZ, UK | INET: pcg@cs.aber.ac.uk