Xref: utzoo comp.lang.c++:3056 comp.lang.lisp:1672 comp.lang.modula2:1436 comp.lang.prolog:1677 comp.lang.smalltalk:1004 comp.lang.misc:2844 Path: utzoo!dptcdc!jarvis.csri.toronto.edu!mailrus!tut.cis.ohio-state.edu!cs.utexas.edu!uunet!pdn!rnms1!alan From: alan@rnms1.paradyne.com (Alan Lovejoy) Newsgroups: comp.lang.c++,comp.lang.lisp,comp.lang.modula2,comp.lang.prolog,comp.lang.smalltalk,comp.lang.misc Subject: Re: C++ vs. Other OOLs Message-ID: <5947@pdn.paradyne.com> Date: 18 Apr 89 19:50:21 GMT References: <2602@ssc-vax.UUCP> Sender: news@pdn.paradyne.com Reply-To: alan@rnms1.paradyne.com (Alan Lovejoy) Organization: AT&T Paradyne, Largo, Florida Lines: 177 In article <2602@ssc-vax.UUCP> dmg@ssc-vax.UUCP (David Geary) writes: >I would like to start a discussion concerning C++ and ool's. I would >like to see comparisons of C++ vs. other object oriented languages such as: > >C++ vs. Modula2 >C++ vs. Lisp >C++ vs. SmallTalk >C++ vs. Prolog >C++ vs. Objective C > > I'd like to know how C++ stacks up against the others as far as: > >It's degree of "object-orientedness" >Speed and portability. -- Portability -- 1) Language portability is a function of how similar the compilers for different systems are and the breadth and depth of STANDARD functions that are provided via STANDARD interfaces. This is largely an extra-linguistic issue that has more to do with the history and culture of different language communities than it has to do with the technical merits of languages as languages. Smalltalk is the winner here, with C++ a strong runner-up. 2) The other issue is how many different systems have implemantions of your language available. C++ wins hands down on this point. -- Speed -- Speed is just as much an implementation issue (compiler AND host CPU) as it is a function of the language (syntax, semantics). Actually, I don't think syntax has any effect on speed at all, unless the translation and execution of the program are both being timed (e.g., an interpretive implementation). The semantics of a language affect speed of execution in several ways: 1) Whether values can be computed during language translation or only during program execution (e.g., dynamic vs. static binding, where the "value" being computed is the address of the object/function which is being referenced). C++ and Modula-2 are essentially tied for first place on this one. 2) How close the expression of an algorithm and/or data structure can be to its mathematically optimum form. Bit manipulation in a language that doesn't know how to talk about bits may suffer a performance penalty. The performance penalty comes from the extra work that must be done in order to simulate what you really wanted to do using something else as a model. The extra work can involve both translations between different representations and adjusting for the differences between the actual behavior of your model and the object/process being modeled. No clear winner is evident, but C++ may have it by a nose. 3) The amount of information that can be provided to the code generator and/or optimizer about the intended use/semantics of objects. Optimization depends upon knowing invariants. If the places from which a variable is referenced are always computable at translation time, then the variable can be kept in a register. Otherwise, it cannot, because the points of access to the value of the variable are not known to be invariant at translation time. Modula-2 has the edge on this metric. 4) The semantic distance between the operations/data structures provided by the source language and the target language (e.g., the machine language). The greater the distance between the semantics of the source langauge and target language operations, the more target language operations will be necessary in order to express the semantics of each source language operation. However, because the space in which this "semantic distance" is measured is multidimensional, it is important to consider along what dimension(s) this distance lies. The semantic distance between integer addition and floating point addition is not in the same dimension as the semantic distance between floating point addition and floating point vector addition, which is in a dimension I will call primitiveness. Floating point addition is more primitive than floating point vector addition. Or to state it conversely, vector addition is "higher level" than scalar addition. The greater the semantic distance between the primitiveness of the source and target languages (assuming the source language is less primitive than is the target language), the more opportunity there is for optimization of translations. This is because the relative semantic granularity of the target language with respect to the source langauge is a function of the difference in primitiveness level. Greater granularity permits greater flexibility in tailoring translations so that they precisely express the semantics of the source construct without unwanted/unnecessary side effects. And the fact that larger differences in primitiveness mean more target operations for each source operation is mitigated by the fact the work performed by the target language operations is inherent to the definition of the source operation, because of the definition of primitiveness. There is no such thing as a free lunch. On the other hand, the implementation of unsigned 32-bit integer math on a machine that only has signed 32-bit integer arithmetic operations would exhibit the opposite effect. The semantic distance may require multiple machine operations for some or all unsigned integer operations in the source. The unwanted side-effects of the semantics of signed integer arithmetic have to be compensated for by means of additional target language operations. The extra work is not inherent to the semantics of unsigned integer arithmetic. Therefore, the extra work is a performance loss. Prolog, Lisp, Smalltalk, Objective-C, Modula-2, C++, in that order. Disclaimer: my evaluation of the languages above is based on my estimation of what could be done with ideal compilation technology. Your mileage may vary, etc. -- Object Orientation -- I don't see object orientation as an end in itself, but rather as a tool for designing languages with great abstractive power. To me, the quality of a language is a function of its ability to EFFICIENTLY and SURELY define, express, manipulate and implement abstractions. However, now is not the time to write my doctoral dissertation of programming language design. This posting is long enough already. The definition of "object oriented language" is open to debate. Instead of debating the minimum set of attributes that an object-oriented language should have, it is more instructive to consider the ideal case. First, some definitions: A class is a set of values and the functions/relations defined on the members of that set. An object is an instance of a class which represents one of the values in the set, that is, one of values of the class. Inheritance is the ability to define a new class in terms of its differences (extensions, deletions, changes) from some other pre-existing class. Prolog, Lisp, Smalltalk, Objective-C, C++, Modula-2 The ideal object-oriented language would: 1) Have user-definable classes. Smalltalk, Objective-C and C++ satisfy this requirement. Lisp and Prolog permit the programmer to define his own class mechanism. There are versions that come with classes built in. Modula-2 has modules, but these differ from true classes because they cannot be instantiated. A module with exports a single opaque type almost qualifies as a class, but it's an ugly and inelegant class at best. Whatever it is, it does not allow class inheritance, a fatal flaw. 2) Have class inheritance. Smalltalk, Objective-C and C++ satisfy this requirement. Lisp and Prolog permit the programmer to include an inheritance mechanism in the implementation of classes. Modula-2 does not support inheritance at all. 3) Allow function/operator overloading. Smalltalk, Objective-C and C++ satisfy this requirement. Lisp and Prolog permit this to be constructed as part of the implementation of classes. The best Modula-2 can do to emulate this is by dynamically binding procedures to procedure variables: it's very, very ugly and suffers from severe limitations. 4) Be completely polymorphic. This is actually the most important requirement for abstractive power. Problems with abstraction mechanisms are usually caused by a lack of polymorphism. Smalltalk and Lisp are highly polymorphic. Next is Objective-C and Prolog. Then C++, and last is Modula-2. I considered defining polymorphism, but I don't have the time right now. If you really want to know, post the question. Someone will answer. Perhaps even me! -- Alan Lovejoy; alan@pdn; 813-530-2211; AT&T Paradyne: 8550 Ulmerton, Largo, FL. Disclaimer: I do not speak for AT&T Paradyne. They do not speak for me. _________________________Design Flaws Travel In Herds_________________________