Why I will never fit in among C++ programmers
I have been actively programming in Python for nearly 13 years, ten of which have been spent as a core developer of the language itself. You could say I have an opinion when it comes to programming languages. That I have taken sides. That I am a programming language bigot.
And you would kind of be right. Obviously I have chosen as my programming language of choice when I can use it. But I’m also not going to sit here and claim that Python is the best solution to every problem, nor that people have to like Python. All I ever ask of people who prefer to use other programming languages is to have a justification as to why and it be rational.
But when I run into people who can’t justify why they prefer to do something in a programming language a certain way without being able to give me what I view as a rational explanation, it drives me up the absolute wall. It’s baseless ignorance that has typically led to people bashing Python or dynamically typed programming languages back when Python wasn’t known by at least name to every programmer out there. I have a bachelors in philosophy and a Ph.D. in computer science: do not give me crappy logic in general, and especially not when it comes to programming.
And yet this happens regularly. For some ironic reason,programmers are curmudgeons like everyone else when something new is presented to them. Programmers work on a daily basis with technology that has revolutionized the world, with tools that they can update on a whim, and yet when provided an opportunity to try something new which could improve their programming lives or just simply be different, they push back. “I like things just as they are.” Yes, my non-programming friends, programmers can often fear change (or at best be indifferent to the point of inaction).
The latest example I came across involves C++11 and its new auto
keyword after a conversation I had with some long-term C++ programmers (I have only been using the language part-time for a year so I typically defer to others for coding best practices). For those of who you don’t know, the auto
keyword does basic type inference for local variables where the type can be inferred by the return type of some expression (e.g. a function call’s return value). For those used to languages that provide type inference it brings C++ in line with languages where you only have to care at API boundaries where types act as documentation/contract (which I’m totally fine with, as are the language designers of Scala, Go, Dart, etc. just to name some newer examples). And for people used to dynamically typed languages this is just one less place to care about types which you have already learned how to live without (hopefully happily).
But when I suggested using auto
in a situation like this:
void UppercaseSomething(SomeStruct& thingy) {
// …
auto uppercase_something = thingy.get_something();
UppercaseString(&uppercase_something);
thingy.set_something(uppercase_something);
// …
}
I had a bunch of C++ programmers tell me they disagreed with my usage of auto
for the string
type. I was given two reasons why this disagreement existed:
- The
string
type is too “simple” to bother inferring - The
string
type is short enough to not need the use ofauto
Up to this point using auto
seemed reasonable to everyone for complicated types and types whose names were a pain to type out. But to someone like me who prefers to live in a world where the only types I ever care about are at the API boundary, being told ‘string’ is too ‘simple’ and/or short for ‘auto’ just flabbergasted me.
When I was told the type was too “simple”, in actuality it was meant to mean that it’s so fundamental to the language that everyone knows it and so knowing it’s a string means everyone knows exactly what methods are available, what it’s memory model and semantics are, etc. By forcing people to write string
it lets people know they are working with something for which they can probably skip reading the docs for.
To this I said “seriously?!?” and then tried to properly articulate myself. To start, if you think string
is so fundamental, what about iterator
? Everyone seemed fine with using auto
for the iterator
type from the STL, and yet that API is rather fundamental in C++. Same goes for vector
. This judgment call over what is or is not fundamental to C++ is just that: a judgment call. Every other language that I know which provides type inference in no way encourages people to bother specifying the type for “simple” things like strings. In other words this classification of string
being so fundamental seemed borderline arbitrary and not to have proven itself as critical in any other programming language out there that provided type inference.
But this also assumes you can’t infer the string
type from either the expression setting the variable or its use around it. In the example above I think UppercaseString()
gives the type away. But if not knowing what type a variable is by strictly reading it truly bothered you then you probably shouldn’t be using auto
anywhere to begin with (this is where Java programmers might be chuckling to themselves).
I would also argue that using auto
makes the key points about variable access of the type more clear. If you had to read const string&
and const auto&
I would argue they are at worst equally readable to deduce that the variable holds a const reference, and at best the auto usage is easier as you don’t have to mentally ignore string
to understand that it doesn’t use pointer access.
And addressing the length argument for typing also seems arbitrary. If I already typed out auto
then who cares about the length? It’s still shorter anyway. But this argument was more for something like int
. Okay, save a character, but is that really all that important? What about when that int
turns into a long
, or a long long
? Now you have no savings or actually typed more.
And even more important, what about refactoring? At least using auto
you have a chance of cutting back on refactoring errors as you don’t have to care about local variables, only non-compatible API boundary types no longer working.
In other words, it felt like I was back in a world where people made claims about a change they were introduced to without having evidence to back up those claims. The only argument I could possibly buy into is the whole “everyone knows what a string is, so when you know that’s the type you should just go ahead and type it”, but even then, switching back and forth between auto
and types deemed too simple seems like it would be mentally annoying at best and taxing at worst as a judgment call I would have to think about every time I touched/wrote a variable declaration. In other words not worth it in my book to make the distinction, especially as no other language with type inference that I have come across has suggested that kind of selective type declarations for local variables.
If people have suggestions or alternative explanation as to why everyone else was right I’m quite ready to listen and try to understand because I would like to understand in order to be a better C++ programmer and to understand the mindset.