C++ sucks — the primitive type <-> string conversions
Since I had a lot of people telling me that no, C++ doesn’t suck, I said I would write in full some of the reasons why C++ does suck. I called it C++ sucks to make sure that people do understand what I refer to. So, without further ado, let’s see today’s topic.
The C++11 standard defined new functions for conversions between primitive types and strings. A set of functions to transform primitive types into strings and vice-versa. Let’s look at their proposal:
string to_string (int val);
string to_string (long val);
string to_string (long long val);
string to_string (unsigned val);
string to_string (unsigned long val);
string to_string (unsigned long long val);
string to_string (float val);
string to_string (double val);
string to_string (long double val);
int stoi (const string& str, size_t* idx = 0, int base = 10);
long stol (const string& str, size_t* idx = 0, int base = 10);
unsigned long stoul (const string& str, size_t* idx = 0, int base = 10);
long long stoll (const string& str, size_t* idx = 0, int base = 10);
unsigned long long stoull (const string& str, size_t* idx = 0, int base = 10);
float stof (const string& str, size_t* idx = 0);
double stod (const string& str, size_t* idx = 0);
long double stold (const string& str, size_t* idx = 0);
I only added the string versions (the wstring versions are quite similar). So here are the problems with this API:
- to_string contains an underscore. This is one of the most painful characters to type on a standard keyboard – it’s a lot harder to type than most other SHIFT+key combination. I would not use an underscore in an API.
- In the standard there are no clear conversions from the standard types intXX_t/uintXX_t – they will be done automatically via the functions defined above. Most importantly, there is no conversion for int8_t and int16_t (aka short int or WORD for senior citizens still using that).
- There is no standard conversion for bool – no canonical string representation for it (“true”/”false”), therefore no clean/clear way (standards defined) to serialize a boolean value.
- The ANSI C functions were extended with the const string reference (they used to take only a const char * as the first parameter). That’s a good thing. But.
- All the string-to functions are shortened, they are more of a mnemonic and
- The functions refer to types that are not defined in the <stdint> header – as a matter of fact they refer to the loosely defined int, long and long long types (they are defined loosely in the standard for a good reason too).
- The functions receive a size_t* parameter that is set by default to 0. Not nullptr, but 0. At least that’s how the CPPReference.com site has them.
- The functions throw an exception when the conversion fails. I am quite unsure this is the way things should work, since very few other standard functions throw exceptions. I wonder what people think about this.
How can things be done better? First, instead of defining primitive types you can define classes like Int8, Int32, Int64, Int128, and have ToString calls on them (yes, I used proper capitalization, sorry for my sin). They can be made to compile and be used as efficient as the primitive types, but would allow programmers to write better/cleaner code.
And unify the API. Make it consistent – use itos, for example, if you want to go down that road, or string_to_integer, even to_integer if you prefer that road, but don’t make it to_string and stoi work as a natural pair, because they don’t.