2 ms·
IIRC one of the reasons Apple passed on BeOS was that the lack of a stable C++ ABI made app dependencies on the OS classes very fragile. For example, API classe
by cageface 15y ago
IIRC one of the reasons Apple passed on BeOS was that the lack of a stable C++ ABI made app dependencies on the OS classes very fragile. For example, API classes had to be padded out with dummy members to make room for later non-breaking additions to apps.
Is this still a problem? Isn't this why just about every other OS exposes it's lowest level APIs as C apis?
- pmjordan 15y agoIf the Apple story is indeed true, there's a certain irony to it: device drivers in the OS X/iOS kernel are written against a C++ API called I/O Kit. For forward-compatibility with newer kernel versions, all the public classes contain a significant number of dummy virtual functions, and many also have a pointer member variable called "reserved" so they can later add new fields if they need to without changing the class size. E.g.: http://www.opensource.apple.com/source/xnu/xnu-1699.24.23/iokit/IOKit/IOMemoryDescriptor.h http://www.opensource.apple.com/source/xnu/xnu-1699.24.23/io... - note the ExpansionData * reserved; member variable and the block of private: OSMetaClassDeclareReservedUsed(IOMemoryDescriptor, 0); #ifdef __LP64__ OSMetaClassDeclareReservedUnused(IOMemoryDescriptor, 1); OSMetaClassDeclareReservedUnused(IOMemoryDescriptor, 2); OSMetaClassDeclareReservedUnused(IOMemoryDescriptor, 3); OSMetaClassDeclareReservedUnused(IOMemoryDescriptor, 4); OSMetaClassDeclareReservedUnused(IOMemoryDescriptor, 5); OSMetaClassDeclareReservedUnused(IOMemoryDescriptor, 6); OSMetaClassDeclareReservedUnused(IOMemoryDescriptor, 7); #else /* !__LP64__ */ OSMetaClassDeclareReservedUsed(IOMemoryDescriptor, 1); OSMetaClassDeclareReservedUsed(IOMemoryDescriptor, 2); OSMetaClassDeclareReservedUsed(IOMemoryDescriptor, 3); OSMetaClassDeclareReservedUsed(IOMemoryDescriptor, 4); OSMetaClassDeclareReservedUsed(IOMemoryDescriptor, 5); OSMetaClassDeclareReservedUsed(IOMemoryDescriptor, 6); OSMetaClassDeclareReservedUsed(IOMemoryDescriptor, 7); #endif /* !__LP64__ */ OSMetaClassDeclareReservedUnused(IOMemoryDescriptor, 8); OSMetaClassDeclareReservedUnused(IOMemoryDescriptor, 9); OSMetaClassDeclareReservedUnused(IOMemoryDescriptor, 10); OSMetaClassDeclareReservedUnused(IOMemoryDescriptor, 11); OSMetaClassDeclareReservedUnused(IOMemoryDescriptor, 12); OSMetaClassDeclareReservedUnused(IOMemoryDescriptor, 13); OSMetaClassDeclareReservedUnused(IOMemoryDescriptor, 14); OSMetaClassDeclareReservedUnused(IOMemoryDescriptor, 15); dummy methods. There is also a system in place for the linker to patch the vtables of dynamically loaded classes (i.e. third-party drivers). They've also built an Objective-C-like Class/metaclass system in C++ via macros for I/O Kit, for some very basic reflection (mainly to keep track of whether instances of a class exist, and if not, unloading the kernel module).
- pjmlp 15y agoI never heard this story before. Mac OS X drivers are written in C++. Symbian is fully written in C++. The new WinRT API for Windows 8 is C++ based along as the user space driver framework. There is no reason why Apple could not have defined a standard C++ ABI in BeOS, if that was the reason. The decision to take NeXT instead of BeOS, surely did not have anything to do with technical merits of the underlying systems.
- cageface 15y agoI think it's not so much the problem of an ABI but the fact that changing base classes in C++ forces client code to be recompiled because offsets of members and vtable entries change: http://haiku-os.org/legacy-docs/benewsletter/Issue2-25.html http://haiku-os.org/legacy-docs/benewsletter/Issue2-25.html Apparently Apple gets around this the usual way by padding out their API classes with extra unused members. I wonder what the solution is in Windows 8 & Symbian.
- gecko 15y agoWinRT gets around it because it doesn't really export C++ the way you're thinking. What it exports are basically COM objects with a bunch of extra CLR-style metadata. COM avoids the C++ issue because it only allows you to consume interfaces, and, for all Windows compilers when COM was invented (and obviously since), vtables are always in a set location. So the trick is: 1. Never change existing interfaces 2. Always add new interfaces to the end of the vtables When you want a COM object, you instantiate it, but you don't work with it directly; you ask for the interface you want to use to talk to the object. As long as the object vendor maintains the old virtual methods, the worst that happens is you ask for the old interface and everything works as normal. This works very well with only a minor speed hit. I think right after //build, I could tell you how they used CLR metadata to extend the system out to supporting subclassing, but I just honestly don't remember. Similar general idea, though; they still avoid the problem by not actually hitting it.
- pjmlp 15y agoYeah, I left that a bit in the air. One can see COM as a kind of operating system OO ABI. OS/2 SOM was better, but never got much following.