I’ve been thinking about some possible features C++ could have, does anyone know why they aren’t supported?
- Member functions for built-in types. This may just not seem necessary, but an interesting feature nonetheless. Example pseudocode:
int int::getFirstBit(void) {return *this & 1;} ... int a = 2; a.getFirstBit();This may seem useless, but it shouldn’t be hard to implement either. With this springs up the following thought: - Member functions outside class definition. I don’t see why this shouldn’t be supported, except for conflicts with access restriction (public,protected,private,etc.) and encapsulation, but perhaps only
structscould have this feature. - Operator overloading for non-object types, a use for this could be for pointers or arrays.
I know these features aren’t necessary for much, but they still seem cool. Is it because they don’t seem necessary or because they can cause many headaches?
Part of one part of the other. Every new feature that is added to a language increments the complexity of the language, compilers and programs. In general, unless there is a real motivating need (or the new feature will help in writing simpler safer programs) features are not added.
As of the particular features you suggest:
1- Member functions for built in types
There is no need, you can do anything you want to do with a member function with a free function for the same cost and with the only difference in user code that the argument to the function is before a
.or inside the parenthesis.The only thing that cannot be done with free functions is dynamic dispatch (polymorphism) but since you cannot derive from those types, you could not have polymorphism either. Then again, to be able to do this you would need 2.
2- Member functions outside class definition.
I understand that you mean extension methods as in C#, where new methods can be added to a type externally. There are very few uses of this feature that are not simple enough to implement without it. Then there are the complexities.
Currently, the compiler sees a single definition of the class and is able to determine all member methods that can be applied to an element of the type. This includes
virtualfunctions, which means that the compiler can at once determine the virtual function table (while vtable is not standard, all implementations use them). If you could add virtual methods outside of the class definition, different translation units would be seeing different incompatible view of the type. Dispatching to the 3rd virtual function could be callingfooin one .cpp file butbarin another. Solving this without postponing a big part of the linking stage to the loading of the binary into memory for execution would be almost impossible, and postponing it would mean a significant change in the language model.If you restrict the feature to non-virtual functions, things get simpler as the calls would be dispatched to the function directly, but nevertheless, even this would imply other levels of complexity. With a separate compilation model as in C++, you would end up having to write headers for the original class and the extension methods, and including both in the translation unit from which you want to use it, which in most cases you can simplify by just declaring those same methods in the original headers as real member methods (or free functions, free functions do form part of the interface of user defined types!)
Additionally, allowing this would mean that simple typos in the code could have unexpected results. Currently the compiler verifies that the definition of a member function has a proper declaration, if this was allowed that check would have to be removed, and a simple typo while writing the name in either the declaration or definition would cause two separate functions rather than a quick to fix compiler error.
3- Operator overloading for non-object types
The language allows for overloading of operators for all user defined types, which includes classes and enumerations. For the rest of the types, there is a set of operators that are already defined with precise semantics that cannot be changed. Again with separate compilation model, it would mean that
1+2could mean different things in different translation units, in particular the exact combination of includes could change the semantics of the program, and that would cause havoc –you remove a dependency in your header, and that removes an include that contains the overload forconst char* + int, which in turn means that the semantics of"Hi" + 2in code that included your header changes, from the user defined operation to yielding a pointer to the nul terminator of the string. This is really dangerous, because it means that a simple change in one part of a program can render other parts of the program incorrect.Even for combinations for which there is no current meaning (
char* + int*) you can use a regular function to provide the same operation. Remember that you should only overload an operator when in the domain that you are modeling that operation is naturally understood to have that particular semantics, which is why you can overload for user defined types, but pointers are not part of your domain, but rather part of the language, and in the language there is no natural definition of what"Hi" + new int(5)means. Operator overloading has the purpose of making code more readable and in any context for which there is no natural definition, operator overloading has the exact opposite effect.