5 ms·
I don't hate C. I'd rather program in C than C++. There's a "uniformity" and simplicity about C that makes it beautiful. You've got structs, functions, and p
by FrancoDiaz 10y ago
I don't hate C. I'd rather program in C than C++. There's a "uniformity" and simplicity about C that makes it beautiful. You've got structs, functions, and pointers...that's it.
I remember reading some of ID's engine code and admiring how well I could follow it and know what's going on. With C++ and other OO languages, it's much harder.
Don't get me wrong, I'm not going to write my next web app in C, and there's some obvious benefits to the features that C++ offers, but C++ ain't beautiful.
- sqeaky 10y agoComments like this perplex me. I am a full time C++ dev and I could just rewrite your comment woving the "++" to the other "C". Really like that I can create a class that stores all the knowledge of one concept internally and if I wrote that correctly I never need to look inside it again. Even better, if I document the contracts of using a class I can carefully optimize it and have broad performance effects with small code changes. Things like std::string are just so much easier to work with that their C counterpart and things like std::filesystem::path simplify (or use the boost one if you don't have C++17 yet) so many things and doesn't even have a C counterpart. I point these out as simple examples but in all the code bases I have worked on there are similar examples, like most games a class to represent 2d and 3d points, which are used to define AxisAlignedBoundingBoxes, which are needed for collision detection algorithms which them selves need several classes to describe. Then I can build systems of a size and complexity I literally could not comprehend without those abstractions. And then the compiler enforces them for me so other people can use them safely as well. Why is it so much harder to do this in C if C is so much "simpler".
- btilly 10y agoC++ has the issue that there are a lot of ways to hide magic, and a lot of hidden magic can blow up in unexpected ways if it interacts badly with other parts of the language that you do not understand. The result is that you really need to stick to a subset of the language that has been chosen to work well together. Safely adding to that chosen subset is challenging. And it just takes one developer to create a major headache. See, for example, https://google.github.io/styleguide/cppguide.html#Exceptions https://google.github.io/styleguide/cppguide.html#Exceptions documenting why Google is not willing to allow even something as basic as exceptions to be used in C++ code.
- sqeaky 10y agoEvery language can hide stuff. Classes, templates and operator overloads are just pretty wrappers for functions with better designed conventions for the common cases. Anyone can write "hidden magic" in any language with anything like these abstractions. It is particularly easy to make this hidden magic in C. For example, there is no way to express who has ownership of a pointer or when a function expects a pointer or an array. I have seen plenty of C libraries that document things like this, but for each that does there are 3 that don't. For each one does document things like that, they do it differently with different conventions but for the same reasons, but I cannot even use common idioms to be safe I must understand every part of each library I call. It is much more clear what is going own in C++ when a function accepts or returns a std::unique_ptr and I cannot screw it up without trying hard. What seems more important to me is exposing the relevant parts of the software when needed. If I care about the business logic (Even if its nots a business app... HP and Mana can be considered the business logic of a game) it can be hard to tease that out when lots of "hidden magic" is shoved in my face. But when I need to handle a new file format that the business logic requires indirectly I don't want to mess with the business logic. Having more tools to cleanly express this helps. So have a type that handles this IO while some other type handles business logic is indeed changing magic into "hidden magic", but it is also enforcing separation of responsibilities. Something much harder to do when your only real tool of abstraction if functions. The only people I have met in real life that stick to anything like the "hidden magic" argument are the same people who advocate for single large functions. These people like their function on the order of hundreds or thousands of lines so they can "see everything". You aren't doing that are you?
- btilly 10y agoThe problem is not so much hiding stuff. It is being surprised by the interactions between features. The "can't get there from here" like trying to printf to an iostream. If you're not careful, simply scanning through a large file is several times slower than other languages. Template magic makes seemingly reasonable type names blow up into insanely hard ones to figure out. There are non-obvious patterns that you have to know such as RAII. And good luck if you want to make things portable! I remember at Google being asked how I checked in unit tests that broke integration tests. Turns out that GCC and Clang disagreed on whether a friend of a subclass can see protected elements in the parent class. The local language lawyer decided that gcc was right, sent off a bug report to Clang, and I had to make my little unit test class a friend of the parent class as well. Maybe I was unlucky, but why does this sort of thing not happen to me in other languages? In other languages I am consistently able to read up on the language syntax and features, implement things within my knowledge, catch my bugs with unit tests, and have a basically working system. I've had this experience with C, Lua, Perl, Ruby, Python, PL/SQL, Java, JavaScript, etc. But C++ finds ways to astound and surprise me. Perhaps if I was a full-time C++ developer I'd learn all of the corners and would simply be productive. But the last time that I wrote a non-trivial C++ program, there wound up being multiple things which worked right in unit tests but not the full program until I ran Valgrind and followed suggestions that I would have had no way of figuring out on my own. Yes, I'm aware of how easy it is for third party libraries to be bad. From dangling pointers in C to monkey patching in Ruby there is a lot of crazy stuff that can be screwed up by third party developers. But C++ is the only language where I had trouble not screwing myself up.
- baka 10y ago"I remember reading some of ID's engine code and admiring how well I could follow it and know what's going on." Npte though that id hasn't really created an influential game in 15 years and arguably the game of the century (Minecraft) was programmed, badly from what I hear, in Java. People often say that "you can write good C code" without considering what you're giving up in terms of architecture and creativity.
- jstimpfle 10y agoWriting good C code also means knowing when to use another language on top. Scripting languages such as Lua are commonly used in the games industry.
- uabstraction 10y agoI think this says more about John Carmack's devine software engineering talent than it does about C++. I've seen some slick looking C++, and I've seen some flat out atrocious C (and vice-versa). Even Carmack decided to switch to C++ for iD Tech 5.