Tools masquerading as languages, maddening syntax, dusty old code that just won’t die—here's what has us shaking our fists. The advice to not carry a grudge may be well-meaning, but it certainly didn’t come from anyone who’s wrestled with a computer for a living. Toil for any amount of time with the infernal logic of a programming language and you’ll know the horrors of the inky void where the worst bugs dwell. Fans love to tout the advantages of their favorite programming languages and sing of the intuitive magic they’ll bring to your coding fingers. Nearly every programming language was created by someone with a grand plan for simplifying their programming chores, and the creators usually succeed—at least in that narrow sense. The problem is that there are often secondary or tertiary effects that aren’t as wonderful. For all the good that programming languages bring, there’s always some hassle, some annoying quirk or inconsistency that ruins an evening, a weekend, or even an entire fiscal year. Alas, we developers can’t do much about it. The installed base may be too large to jettison the language that irks us. The boss may love a stack so much they refuse to hear the screams from the cubicle farms. Often, there’s not even any agreement about what might be a good replacement. The cruel truth is that there may be no better options. We’re already using the best tools that humans can build. From Gödel and Turing, we’ve learned that logical mechanisms have sharp edges. Sure, maybe it’s our own fault, we humans, for misusing or misprogramming. But when a programming language forces our brains into weird yoga poses, it’s hard not to blame it for our discontent. Still, understanding the limitations of different programming languages makes it easier to program around them. If we can’t permanently delete the languages from our repositories, we can try to understand and anticipate their idiosyncrasies. And besides, venting sometimes helps. Here are eight programming languages we love to hate, but also can’t live without. C C is a language that might better be called a “portable assembler” rather than a complete computer language. Does anyone like writing separate header files? Has anyone used the preprocessor for something elaborate without going slightly mad? In theory, we’re supposed to be able to use the power of the pointer arithmetic to do clever feats, but does anyone risk doing more than allocating data structures? Is it even a good idea to be too clever with pointers? That’s how code breaks. If you’re able to be clever, it often requires writing a very long comment to document it, pretty much sucking up all the time you saved by being clever. Can anyone remember all the rules for writing C code to avoid adding all the possible security holes, like buffer overruns? But we have no choice: Unix is written in C, and it runs most mobile phones and most of the cloud. Not everyone who writes code for these platforms needs to use C, but someone has to stay current with the asterisks and curly brackets, or else everything will fall apart. Even the Unix people are starting to move away from C. In the last few years, some of the patches for the Linux kernel started appearing in Rust. The developers feel that the language’s more rigid structure will prevent some of the security holes that C developers leave behind when they’re being clever. This transition, though, will take years and we’ll probably be writing and chasing C pointers for longer than we run Cobol. JavaScript JavaScript’s creators tried to make something modern. It’s too bad that in their brilliance they’ve forever doomed us to a life of counting curly brackets, square brackets, and parentheses—while ensuring that they’re all properly nested, of course. Between the anonymous functions, the closures, and the JSON data structures, our pinkies get a real workout hitting those keys. Then there are the weird details. If x is a string that holds the character for 1, then x+1 will produce the string 11 and x-1 will produce the number zero. Does anyone remember the difference between false, null, NaN, and undefined? They sound similar, but why does JavaScript have all four of them? And why don’t they behave consistently? And then there’s the rapid change. New JavaScript often looks nothing like old JavaScript, thanks to newer features for unpacking and packing, spreading or unspreading objects and arrays of objects. The code looks like a sea of double quotes, triple quotes, double question marks, and triple dots. Remember that “=>” is an arrow that invokes a function but “>=” is a way to compare numbers. The new features are great if you love them, but the rest of us are confused and stuck juggling ECMAScript version numbers and wondering if some browser will barf when fed some version of the code. Alas, the internet, the web, and a bazillion browsers aren’t going anywhere. Then the supersmart Node.js team came along and built a platform for running JavaScript on the server. Now, it’s one of the most popular ways to build modern, progressive web applications. Coders are celebrating the freedom of isomorphic code that runs on both the browser and the server. It doesn’t matter how much developers complain. We’ll be juggling anonymous functions and closures for decades. PHP PHP is not really a computer language; it’s more of a tool for adding a bit of smarts to static HTML. You can store information in a database and concatenate it with static tags. There might be a few more features, but it seems like all we do with PHP is glue together strings we grab from a database. Well, that’s how it was. Some of PHP’s creators have taken all our complaints to heart and added features like a stronger type system, smarter strings, and better integration with MySQL. PHP is better for it, and it supports more elaborate codebases. All of that sounds good, but don’t get too excited about the improvements. At the same time the developers are adding new features, they’re deprecating some of the old ones. That means it’s only a matter of time before the old code stops working. Arguing about toyish code or baby syntax isn’t worth the trouble. Between WordPress, Joomla, and Drupal, most of the content on the web is delivered through PHP code. Then there’s Facebook (or Meta), which was largely written in PHP and continues to suck up a significant percentage of our time. We should just be happy that Facebook built the HipHop Virtual Machine (HHVM), inspiring Zend to create PHP 8.2. These new PHP engines are often twice as fast, an irresistible speed boost that will save millions in electricity and ensure we’ll all be writing PHP long into the future. Cobol Cobol began life in 1959 and should be obsolete by now, with its complex syntax filled with hundreds of restricted words. Yet Cobol lovers keep generating new versions, borrowing ideas from other languages, and bolting them onto a frame that’s more than 60 years old. Did you know there’s something called Cobol 2014? It includes dynamic tables, an idea that people have been trying to get into the language since 2002. And then there’s Visual Cobol 8.0 which can link your Cobol up with Java or .NET code making it easier than ever to keep your old code running and running and running alongside more modern stacks. We may have better tools for writing business logic to manipulate databases, but no one seems to bother because it’s easier to buy a bigger computer and keep the Cobol code going. Cobol lovers point out that old software logic never wears out so why risk introducing errors by trying to update it? As I type this, there are 346 jobs listed on Dice.com with the word Cobol in them. There are Cobol jobs in insurance companies and defense contractors everywhere. Early mainframe adopters still use Cobol to get the job done. Computer scientists may recoil in horror, but as long as customers are lining up, the bosses will say, “If it ain’t broke, don’t fix it. Just buy a bigger mainframe.” R R was developed for data science and is still used widely by data scientists, although some have switched to Python because they find R too arcane. Some traditional programmers are thrown off by the interactive nature of R, sometimes called its “scratchpad mode.” Anyone who needs to add a few numbers or compute the standard deviation of a data set can just type a few characters into R’s command prompt and get the answer immediately. R is just as much a tool you use as a programming language for building things. The language itself can be a bit odd and confusing. Many of the commands are designed to be quick and concise, which is great if you’re juggling test tubes in the lab and asking R to compute a number on the side. Punctuation like the comma is incredibly powerful and I’ve found that the solution to my woes was adding another comma. Hours of headaches, all for the want of one of the tiniest punctuation marks. R’s syntactic mysteries and data structure challenges frustrate data scientists—and they will for years to come. The installed base of R packages and libraries is almost irresistible. The R ecosystem is broad and growing. Many of the packages are open source and ready to answer your questions or your boss’s demands with a quick graph or regression. It’s just much easier to pull out your hair figuring out the double brackets in R than it is to rewrite the endless packages in your favorite language. Java The virtual machine and the libraries may date from the ’90s, but Java’s syntax is stuck in the 1970s when C was created. Automatic memory management seems like a big step forward until your code decides to abdicate while garbage collection takes control. Android developers exchange tips on when to politely request a garbage collection in advance to ensure that the garbage collector doesn’t start up in the middle of an important event, like a phone call to 911. Java programmers have complained for a long time about many issues with the language, some of which have been fixed or at least addressed by Oracle. But this creates a new problem. Some of the newer code and libraries can’t work with the old VMs. I spent a day trying to wrangle java.lang.UnsupportedClassVersionError but could not find a permanent solution. It’s almost as if each version of Java after 1.4 is a different language. The Java release cycle spins out new versions with new features at a faster pace than ever, which sometimes looks like the salami is sliced thinner but they’ve sped up the assembly line. This is great if you need the new features, but it just means even more complexity in keeping your code stable and running. None of these issues matter. Java is a foundation for the web and mobile phones. It’s still the first language taught in many high schools. The collection of libraries is deeper and more valuable than almost any other language. Not only that, but many of the clever new languages secretly rely on Java’s foundation because they’re compiled to Java byte code. Java will always have a place in the stack. Just accept it. Python Python is a modern language that appeals to younger developers. The punctuation is sparse, and the code looks a bit cleaner. What’s not to love? Instead of counting and balancing curly brackets to define blocks of code, we’re counting white space and making sure columns align. Just make sure you’re using a monospace font! Well, for one thing, there’s the gap between Python 2.7 and 3.0. The big change, though, isn’t the only one and many of the newer versions include updates that might break your code. Functions that once returned 0 or 1 now return booleans in Python 3.6. Words like “async” and “await” became reserved keywords in version 3.7. The Python team, though, has heard the grief of coders who can’t keep track of the versions and most of the changes seem to be additions and new features not fixes that break your old code. Yes, the team has no choice if they want to keep improving the language. But anyone trying to maintain a bigger project and work with older libraries will forever be checking to see which version of Python is installed. This gets even more complicated because many of the popular Linux distros use Python for system tasks. Even if you can keep the versions straight for your code, the distro may be using a different one. Just last year, my Python code stopped working when I upgraded the underlying version of Linux and this upgrade quietly updated the version of Python on the box. Whoops. But the language is so deeply embedded that we’re stuck with it. None of these objections matter because the soft science crowd has fallen for Python with all the warm, fuzzy emotions that kept them out of the hard sciences. Biologists and economists think Python is the one. Some even propose requiring Python code in new prospectuses for stocks and bonds so that investment bankers will be able to bamboozle us with Python instead of fractured lawyer-speak. The bandwagon has left the station, and it’s full of soft scientists. Swift If you want to charge your iPhone you need a special plug and if you want to program it, well, you also need to use a special language, too. Apple always needs to do things its own way. It’s not exactly true that Swift is an Apple-only language. A small group of dedicated people celebrate using Swift on a server. But for the most part, it’s just a special not-so-secret handshake language that can only be used inside the Apple secret fort. As languages go, Swift is better than Objective C, the other not-so-secret handshake language it’s largely replaced. The punctuation is saner; the typing is better; the header files are gone; and the memory management is more automatic. But for all of those improvements, life is still not easy for developers. The language is big and that makes it harder to absorb. The books go one for hundreds of pages detailing all the fancy new features from elaborate types to tuples to protocols. It’s impossible to list every clever and obscure idea that got bolted onto this dreadnought. Other companies have taken a different approach. Google tried to make Go as simple as possible to, in turn, make the code simpler to read and understand. Swift’s endless clever features may end up saving time occasionally when a programmer knows how to use them, but there’s a good chance that the next several programmers who read the code might not be so familiar with them. Swift has so many clever features that it’s hard for anyone to master them all. The best example of this cleverness overkill may be the way that any coder can create new operators out of any random set of Unicode. It’s great fun the first time you use an emoji in your code, especially one of the emotionally pungent ones, but the next person to come along is going to be confused. But none of this matters because Apple loves its language as much as it loves going its own way. Sure, it would be nice if you could swap code with the world outside Apple’s secret fort, but that’s not going to happen. So the best solution is just to study up on Swift and, maybe, stick to a small, core subset of the features. Programming LanguagesJavaJavaScriptPythonR LanguageSoftware Development