Xref: utzoo comp.lang.c++:11893 comp.object:2616 comp.lang.objective-c:179 Path: utzoo!utgpu!news-server.csri.toronto.edu!cs.utexas.edu!uunet!mcsun!ukc!dcl-cs!aber-cs!athene!pcg From: pcg@cs.aber.ac.uk (Piercarlo Grandi) Newsgroups: comp.lang.c++,comp.object,comp.lang.objective-c Subject: Re: Static typing and OOP efficiency Message-ID: Date: 27 Feb 91 19:09:41 GMT References: <1991Feb16.121825.15353@gpu.utcs.utoronto.ca> <27BFDF44.3EA6@tct.uucp> <27C523A2.2155@tct.uucp> Sender: aro@aber-cs.UUCP Organization: Coleg Prifysgol Cymru Lines: 143 Nntp-Posting-Host: odin In-reply-to: chip@tct.uucp's message of 22 Feb 91 13:58:57 GMT On 22 Feb 91 13:58:57 GMT, chip@tct.uucp (Chip Salzenberg) said: chip> [ Please direct followups appropriately. ] chip> But I am not willing to jump on the Objective-C bandwagon, if only chip> because static typing is a useful way to avoid a great deal of chip> run-time messaging and debugging overhead. chip> According to pcg@cs.aber.ac.uk (Piercarlo Grandi): pcg> I think this is a grave mistake of perspective, at least for application pcg> programming, for the following reasons: pcg> pcg> 1) Objective C does allow you to declare explicitly the type of objects, pcg> via a cast like notation. chip> Allow, yes, but not require. Just like C++, in the opposite direction. We should not be arguing about which way the default should be; that's pretty irrelevant. chip> Besides, as far as I know, there is no guarantee that the message chip> set supported by a given class will not expand after the users of chip> that class have already been compiled. Same problem in C++, really, but in C++ it triggers recompilation instead of just relinking like in Objective C (if you are happy with dynamic overloading). The idea in Objective C is that you resolve statically what you can, and turn to dynamic overloading for what you cannot. chip> So compiler is not free to reject a message out of hand on the chip> basis that the recipient will not understand it. Yeah, instead of rejecting, it just gets resolved dynamically instead of statically. In C++ you simply don't have this option in the general case. pcg> 2) In any case even in C++ there is a tendency to declared everything pcg> virtual, just in case, so you still have dynamic dispatching. chip> I only make a function virtual if I have an explicit reason for chip> doing so. That's what I do too, but I tend to have complete control over the shape of my programs, because I tend to do monolithic standalone systems software. The problem is that OO, at the application level, is supposed to be about more reuse, and therefore libraries. When you write a library in C++ you tend to make everything virtual that can plausibly be, just in case. The people at AT&T did not make certain things virtual in the 'iostream' library and a lot of people are unhappy about that. But after all virtual is not that bad; in many cases overloading resolution can still be done at compiletime (especially if you use appropriate casts), just like Objective C can. pcg> 3) Dynamic dispatchin can be made impressively fast, by the use of pcg> various tricks (hashed tables, type deductive compilers, clever pcg> linkers, hinting and caching). chip> There's no way, however, that the dynamic dispatching of chip> Objective-C can outperform even a virtual C++ member function, chip> much less a normal member function, assuming that the C++ chip> implementor was in her right mind when she wrote the code chip> generator. First, the speed on non dynamically overloaded messages is exactly the same in C++ and Objective C, and as you note later, this is the prevalent case. As to dynamic overloading, C++ has an advantage in that it has manifest types with bounded runtime overloading, while Objective C has latent types with unbounded runtime overloading. This means that C++ can use double indirection into vtbls, where Objective C has to use hash tables or caching, hinting, and the like. So Objective C is at a disadvantage here. There are some questions though to consider: [1] How large is the extra cost? [2] How frequently is it incurred? [3] Does it make a large difference to the overall runtime? The answers are, according to some scant but reliable evidence: [1] Possibly around 100-200%, if you are very clever. [2] Depends on the application, but usually not often. [3] For most applications, a quite small difference. I would really like somebody who has got both compilers, e.g. a NeXT user, to do a table with the relative costs of calling non virtual in the two languages, and then virtual. chip> [ ... C++ ... ] permitting most (yes, _most_) member functions to chip> be non-virtual. Agreed, that's why it is not so important that Objective C is at as disadvantage for virtual functions. Actually C++ has some advantages over Objective C, but these are not speed advantages related to dynamic overloading. They are that static overload resolution is done on all arguments to a function and not just the first, and possibly multiple inheritance. Efficiency advantages that are important for systems programming, but not for most applications, are C++ support for inline functions and objects. These are IMNHO far more important than the relative speed of relatively infrequent dynamic overload resolution. I am not very current on Objective C, so maybe inline functions have been added as well as inline objects. Hopefully the new Objective C book will come out eventually. pcg> On the other hand I have been serious considering writing an OS kernel pcg> in bytecoded OO scheme, as after all a well designed OS kernel should be pcg> very rarely invoked and so on... chip> I hold almost the opposite view: A well-designed kernel is fast enough chip> so that applications programmers will call it often, not fearing that chip> the frequent calls will make their application inefficient. Look at chip> the periodic brouhaha about using spawn() instead of fork()/exec() for chip> efficiency, all of which is moot if fork() is implemented efficiently. Of course, but my kernel architecture does not look (internally) anything like Unix; the traditional Unix kernel architecture is acknowledged to advise fairly large granularity of interaction with it, even if it written in C, but other architectures need not have the same property. For example in my kernel architecture fork() is not a kernel primitive, and neither are the scheduler, memory manager, or drivers, for that matter. My kernel architecture just defines capability based communications channels between user state modules, and these do all the work, and be written in any language whatsoever. If you have a more conventional frame of mind, my kernel architecture is just that of a dynamic linker. -- 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