Language Wars

June 18, 2012 - Games, General Computing, Programming

It is a frequent point of debate in many web communities that contain programmers- or back-seat programmers, as it were, to argue that such and such language is better than another, or “if it was written in this language it would be faster”. A lot of the time this is coming from people calling themselves “real programmers” or at least putting on the air that “real” programmers don’t use managed languages like Java or C#; instead they seem to think that “real” programmers use C. And arguably, any programmer should at least be able to read C. However, a good programmer is defined not by what language they use, but their product. a Program that works is a program that works, regardless of the language it was written in.

Anyway, the idea that C- or C++ is superior to Java- or, more generally, that any language is better than another for speed- comes with the implicit assumption that there is some limit. Because you know what can probably create faster code than C++? C. And faster than that? Hand-tuned assembly. Saying C++ is superior is basically saying that it’s worth it to dump the language-based advantages that Java has over C++ for the speed improvement, but somehow it isn’t worth it to make nearly the same amount of gains by switching to C, or by switching from C to Assembly.

Thing is, unless you choose Assembly language, there will always be a language that can make your program faster. But the thing is that we use Programming languages to try to abstract away the details. Instead of having a series of direct instructions to the Floating Point Unit, placing values on the FPU and CPU stacks to perform operations in Assembly, we simply use C or a higher-level language and give them a in-fix expression as we are used to it. Can you sometimes make such code run faster in Assembly? probably; if you take advantage of U and V pipe-lining, make sure to reduce wait states and memory accesses, and so forth.

The bigger question is, “Is it worth it”. And largely, no, it isn’t worth it. In fact, it very seldom is worth it.

another point is that the primary thing you are doing with a programming language now is interfacing with libraries. C++, C, and Assembly don’t make the Libraries run any faster. On windows if you allocate memory- whether by way of creating objects in Java or C#, using new in C++, using malloc, alloc, or whatever in C, it all boils down to OS-specific functions; in Windows case, all of those eventually become calls to LocalAlloc. (Or GlobalAlloc). But whether you make that call from Java or C doesn’t make that function execute faster.

Sure, you can argue that Java or C# probably has more overhead; from new Object() to the actual Allocation there is probably some garbage collection housekeeping and allocating the various fields. But the fact is that in C you will usually be doing that housekeeping yourself anyway; depending on the nature of the memory allocation and what it is for, you will probably be making a lot of calls to malloc() and free(); and every single time is a tango with the evil poltergeist known as memory allocation problems. accidentally forget to free a block of memory and then reassign the value being used to store the pointer- leak. Accidentally call free twice on the same block of memory? double-free. All that extra code adds up, and while I don’t think it quite equals the time penalties associated with Java, which might accure to about a tenth of a second over a constant year of execution, it certainly takes a toll on anybody trying to work on the code. Having to remember “I have to allocate that structure on 16-byte boundaries, and I need to make sure all the char arrays are packed before I call this function,” etc.

And even then, you could easily eke out a similar performance gain over a C or C++ implementation by completely retooling the entire program in Assembly.

For any number of projects written in Java or C#; particularly Games- you can usually find a number of posts on forusm calling for or at least implying that the game should be re-written in C or C++ “for speed”. But why stop at C or C++? Why not call for the entire thing to be re-written in Assembly? Because it’s not worth the effort. But the thing is, it’s not worth the effort to rewrite it in C or C++, either; by the time any such rewrite is completed, computers will have gained enough speed to make the speed improvement moot. The reason that Assembly language isn’t used is because it is no longer necessary.

Programs used to pretty much have to be written in Assembly to be reasonably fast. QDOS/MS-DOS was originally coded in Assembly language. Same with every early Operating System. But those Operating Systems were dead simple by comparison. Now, C is the main language used for Operating Systems. Did C code get faster? Not really, at least not in comparison to hand-tuned Assembly. but the fact is that if writing twice as much code could make your code 10% faster, it was only worth it if that 10% speed difference actually mattered. With the 386, it did, and could often mean your program showing a chart a full second before your competition. Now, your program running 10% faster can often mean that it shows a chart imperceptibly faster, which is hardly justification for tripling the amount of code, making it difficult to maintain with low-level code, and discarding numerous useful abstractions.

That last word sort of touches on what a Programming Language truly is- just a set of abstractions. Let’s take a simple language construct that exists in nearly every language- the simple if. In assembly, the equivalent is to use a compare instruction, and then use a Jump instruction (for example, JNE (Jump if not equal) to Jump to a specific address. Most Assemblers also add features that don’t directly translate to Machine code, such as Macros, making some of this a little easier. Your typical C if statement might take quite a few lines to perform all the needed compares. But it certainly takes more work. Can you make that if run faster? Well, probably, if you are a skilled Assembler programmer. But most people aren’t, and even in the case that one is they would only do this in a time critical inner loop.

Nowadays, inner loop speed is not as critical as it used to be. While a Assembly rewrite to a critical section of code might make that code 200% faster on a 386, that doesn’t mean it would have the same effect on a modern machine, because modern machines have multiple processors, some of which need to access the cache concurrently; there are also numerous pipelining issues to consider. For the most part optimizing code with Assembly on a modern processor is not a feasible solution.

It used to be that Assembly had to be used for everything. If you used C, you were a loser and your code was too slow for general use. Then it was that C was used for everything. If you used C++, you were a loser and your code was too slow for general use. Now, it feels like C++ is used “for everything”. If you use anything else, your code is too slow for general use.

But the fact is that people sticking to these older- if arguably faster- languages are sticking also to the same languages that have made possible almost every single security vulnerability in every modern Operating System. C code just begs to be buffer overflowed, and the simplest oversight can topple a companies entire network, pass along trade secrets, or otherwise be a gigantic pain in the ass. In today’s networked world, Speed is not something that is required of programming languages, both because if it’s myriad trade-offs, such as costing more programmer time and anguish, as well as the fact that you can always buy a faster computer later. Obviously, as long as the algorithms used are sound, you aren’t going to be getting gigantic gains on your implementations just by switching to another language. Sometimes it can even make things slower. Managed languages are a good idea for Application code- and games- simply because they are for Applications. Games don’t need to be close to the hardware because, like a wife after a long marriage, the hardware hasn’t even been touched in years. All “hardware” interaction is done today either through OpenGL or DirectX, which themselves delegate through software-based drivers anyway.

Computer time is cheap. Programmer time is not.

Have something to say about this post? Comment!