Choosing a Programming Language: So easy, a caveman can do it

1. Introduction
About a week or two ago, I found myself prompting Google and other search engines with questions like, “what is the best programming language?”, “how to choose a programming language?”, “how to interpret performance benchmarks?”, et ad nauseam. I even took a few cheap-o “what programming language are you?” type quizzes (I, in fact, created this “cheap-o” quiz).

Gimmicks aside, being a non-programmer, I neither have the luxury of being dictated languages to learn nor the opportunity to learn perhaps dozens of languages throughout my career. This lead me down a path in which I felt compelled to choose once, and choose right. In my visionquest to find the “right” one, and after weeks of research, I am no closer to nor am I any more certain about any of these answers. In failure, however, I discovered that I had framed the problem incorrectly. Instead of thinking about learning a programming language as a linear endeavor or as an exercise in academia, I should have remembered the wisdom passed down by my illustrious ancestor, the caveman: “every problem looks like a nail if all you’ve got is a hammer”. Even our great fore-bearers knew that it is better to adopt a synergistic array of tools, so why wasn’t this immediately obvious?

Short answer: because I lacked an understanding of programming fundamentals. Because I only had a hammer (Excel/VBA), every problem looked like a nail. Which brings me to my first point: an understanding of how languages and programming paradigms were developed to address various types of problems provides a framework for deciding upon a complementary assortment of tools that are suited for various tasks.

With these thoughts and questions in mind, I humbly submit my analyses for your evaluation.

2. Paradigms
While there isn’t really a “best” overall language, it is important to recognize that some tool are better than others, depending on the task at hand.

To grossly over-simplify, the most basic programming language paradigm is the imperative, which tells the machine what to do, and how to do it. At the lowest end of the spectra are machine and assembly. One notch higher on the imperative level are procedural languages, such as C, FORTRAN, and Basic (the lowest of the so-called “high-level” languages).  The efficacy and efficiency of any solution at this level is highly dependent on a programmer’s experience, inventiveness and ability.

Object-oriented languages (like C++ or Java) were later developed to enhance programmer productivity through the inheritance of object methods. In this way, a programmer can spend less time on telling the machine how to do things, instead relying on reusable code.

Independently of object-oriented languages, declarative paradigms were developed. These paradigms focused on letting programmers tell the machine what to accomplish, and letting the program decide how best to do it. Functional languages, like SQL, rely less on assignment and more so recursion to achieve this end. Logical languages take this even further, foregoing telling the machine what to do, but rather what an answer looks like.

While I’ve omitted many such paradigmatic distinctions, my point is to convey that no single paradigm allows programmers to solve all types of problems in the easiest and most efficient way. It is sufficient to be able to understand the concept of paradigms as it applies to problem sets; reciting them is secondary.

Figure 1: The Basic Paradigms

Table 1: Matrix for 29 Languages with 15 paradigms


3. Intended Uses
Along the same lines, it makes sense to be aware that various languages were created with different use cases in mind.

Table 2: Matrix for 29 Languages with 15 Intended Uses


4. Benchmarking

Benchmarking is one of the most common ways by which to measure and compare language performance. Most commonly, they measure speed, but can also be used to measure expressiveness, efficiency, and more.

The below graph summarizes languages benchmarks on a number of computationally intensive tasks using three criteria. The raw data for the metrics is available at For all the  following criteria, lower numbers are better. The criteria are as follow:

  • Size(B): Corresponds to the average compiled size of code utilized to run task. It is a proxy for measuring language expressiveness; the smaller the number, the more a programmer can accomplish in fewer lines of code.
  • Mem(KB): Measures average memory utilization in kilobytes; lower numbers correspond to more efficient handling of memory.
  • CPU(s): Measures the average number of second to run a task; obviously, faster is better.

Figure 2: Efficient Frontier: Speed vs Memory vs Expressiveness


Table 3: Efficient Frontier: Benchmarks*

  • Benchmarks evaluated using average performance metrics based on the following computational tasks: binary-trees, binary-trees-redux, chameneos-redux, fannkuch-redux, fasta, fasta-redux, k-nucleotide, mandelbrot, meteor-contest, n-body, pidigits, regex-dna, reverse-complement, spectral-norm, and thread-ring. Raw data, accessed February 17, 2013, available online:

Admittedly, a simplified analysis such as this is prone to the “flaw of averages”, meaning that averages fail to demonstrate dispersion and outliers. A few sources have managed to overcome this by displaying performance metrics using star charts:

There are numerous sources and ways to benchmark a programming language’s performance (see:; and, However, there is no way to expediently untangle all of the inherent biases in them (see explanation here). AttractiveChaos combats some of this bias by testing fewer languages with different compilers as a sensitivity/robustness test.

5. Other criteria
Aside from traditional empirical benchmarking, there other considerations. Some of which are quantifiable, while other lend themselves more to qualitative analysis. Below is a short list of criteria by which to compare various languages. This list is not exhaustive nor, with the exception of productivity, ordered in any particular manner.

  • Productivity – For problem-centric programmers, productivity is probably the most important factor. It is also the most inter-related with other criteria.
  • Expressiveness – On the most basic level, an expressive language is a concise language, meaning that it can do a lot more for less code. Programmers disagree on the correct way to measure expressiveness, whether through the number of code blocks, number of characters, or overall size of the compiled code (see one possible solution). Wikipedia also has an interesting take on measuring expressiveness.
  • Aesthetics – RoBlog has a nice post on this facet of a language: “A beautiful language has a clear and uncluttered syntax — neither more verbose than necessary nor more terse than readability allows.  A beautiful language has clear semantics, …should be expressive…, [and] should be efficient.”
  • Maturity – A mature language has been vetted and boasts a large and well-documented library. FORTRAN is often cited as having a very mature library for numerical analyses.
  • Domain Specificity –  A language should respond to your specific needs, possibly including:  Scientific/Quant Analysis; Text/Language Processing; and Image Processing.
  • Speed/Efficiency – Raw speed may not always be necessary, but should never sacrificed unnecessarily. As compilers become more sophisticated and robust, even some of highest level interpreted languages can come within a factor or two of C/FORTRAN.
  • Portability – Portability may or may not a necessity, but it never hurts to be able to deploy across multiple operating systems, and even within a web browser. Portability is one reason why Java has been so well received.
  • Scalability – This is a concern when moving from a research/prototype environment to deployment. Transcribing code from one language to another may be a good academic exercise, but surely one inconvenience as well.
  • Ease – One way of measuring a language’s speed and efficiency starts not at compile-time, but rather with coding. The ease at which a language can be learned is important if this is how you measure productivity.
  • Flexibility – Can your language address a broad array of problems, or is its utility narrowly confined?
  • Price – Even when price is no object, it is. With so many open-source projects to choose from, one should be able to justify an extra expense.
  • Extensibility – Does your language play well with others? Can you use alternative compilers or call on non-native libraries without much trouble?
  • Acceptance/Popularity – While many might eschew popularity as a valid criterion, it is in most cases a useful indicator for traction in any of the previously mentioned categories.

6. Note on Popularity
It has been my experience that the deciding factor for many people has been language acceptance and popularity. Admittedly, popularity is somewhat of positive reinforcement loop: popular and possibly inferior languages stay popular precisely because they are popular in the first place. Unfortunately, this cycle makes it difficult for new and innovative languages to capture an audience. For example, Julia ( which was released in 2012 offers many promising features and advancements in the realm of numerical and high-speed computing, but will have a difficult time replacing the deeply embedded Matlab, R, and FORTRAN. Also, OcaML is often cited as a superior functional language, but has yet to fulfill its potential due to immature and sparse libraries. The examples for this kind of phenomenon are endless (via-a-vis Google’s Go and Dart; DARPA’s responses to FORTRAN: Fortress, Chapel, and X10, etcetera…).

On the other hand, language popularity is good proxy for traction in a number of performance and aesthetically related characteristics. Given that popular languages may or may not be inherently “superior” to their less popular counterparts, their are a lot of good reasons for going with the crowd. One of the main reasons is due to that they are taught in schools. Equally as important is language maturity. If a lot of people are using a language, it is likely to feature mature libraries, a vibrant community presence, and well documented support. In my personal experience, the best resource for trouble-shooting code is simply typing the issue into Google. If the language is in wide use, their is high likelihood that someone has already solved a similar, if not almost identical, problem.

Google Trends, LangPop, and Tiobe provide some good ways to benchmark popularity. The chart below, courtesy of RedMonk, displays 2012 language popularity as measured by the amount of activity on GitHub versus StackOverflow.

Figure 3: Language Popularity on RedMonk
Chart courtesy of RedMonk. Online available: (Accessed February 15, 2013).

7. Programming as an Exercise in Project Management
In addition to programming languages being a set of tools designed to facilitate problem solving, it is helpful to think of problem solving as a project management process. When faced with a problem in which you have control over the tools and methods utilized, you might begin by breaking down the problem into sub-problems. Hypothetically, let’s assume that I am tasked with designing a program to trade stocks, including locating profitable trades, to actually executing them through a broker. Although the entire process can begin and end with an industrial strength language like C++ or JavaScript, I might make better use of time by breaking down the problem into phases such as the following:

  1. Prototyping: pseudo-languages like Excel, Matlab, Mathematica, or R are well suited to rapid-prototyping for data analysis types of applications.
  2. Testing: scripting languages like Ruby, Python, and Perl can often be used as “glue” to implement prototypes into test environments.
  3. Integration/Deployment: once prototypes have been vetted, they can be interpreted and implemented in other languages by “specialist” programmers.

8. Conclusion
The tacit wisdom of adopting “problem-cetric” approach premises on the notion that the proper role of automation is to enhance productivity, not stifle it. In other words, we are the masters, they [computers] are our servants. Trivial and academic pursuits aside, the questions for choosing programming languages are the same ones your prodigious ancestors pondered when flint first struck stone, or when the tension of the sapling was first strung into snare then bow. Likewise, whether your prerogatives are for aesthetic appeal or raw computational speed, the goal, from inception to coding to run time, is always to carry out the most of our productive interests for the least amount of effort. Ask yourself: “Is optimization of speed premature while productivity languishes?”; “Are semantic elegance and lexical simplicity just means by which to further our productive capacity?” Eschewing the “one-size fits all” paradigm, we should be able to call upon a diverse array of tools; ones that compensate for the shortcomings of others, and that complement each other in ways that enhance our ability to solve problems.

In keeping with our problem-solving analogy to choosing a programming language, I am reminded of a recurrent foil with my childhood friends: “If you had to survive in the wilderness and you could only take one tool with you, which one would you take?” There is no one right answer to the existential problem, but we can intuit some heuristic rules which center on balancing domain-specialization, experience-level, and versatility.

In deciding which tool (language) to take into the wilderness (workplace), it is important to attempt to match the types of problems one may encounter with the skill-sets one already possesses. A bow and arrow (specialized application) is great for a trained bowman (professional programmer), but basically useless otherwise. Moreover, a bow (specialized application) is also useless for anything but hunting and self-defense (the applications for which is was designed).

Often, we do not know exactly what types of challenges we will face. Versatility is therefore our best countermeasure against this uncertainty. For example, a carpentry hatchet (crude yet extensible scripting language) is useful in more types of wilderness (workplace) scenarios than the bow and arrow (specialized application).

The standout hatchet tool, in my opinion, definitely corresponds most closely to Python. The Protocols for the Establishment of Python (PEP) 20, (i.e., “the Zen of Python”), elegantly captures the essence of balancing robustness with simplicity and versatility. In fact, I might go as far as to claim that PEP-20 has been a major factor in Python’s success.

After becoming sufficiently proficient with the hatchet, its limitations will become apparent. Fortunately, there is a wonderful multitude of additional options to choose from (in addition to the multitudes of scenarios which invalidate these heuristic rules). Additionally, the more tools one masters, the easier it becomes to master additional tools. As the learning curve flattens, it is natural to begin realizing how incorporating domain-specific tools actually lessens the overall burden of work while also improving the end-result.

Like I said, a caveman could do it.

  • flaie

    I wonder how you built your matrix. I think the entries are false for some of the programming languages. For example OCaml which is clearly a multi-paradigm language, that has lazy evaluation, generic through polymorphism, arrays also. What’s “structured” that only Dart and C# are sharing ?

    Maybe you should explain better what are the 15 paradigms, or link to an explanation for them and why you choose to set TRUE/FALSE for them.

    Same for intended uses, OCaml is largely used for education, at least in France where it used to learn the functional paradigm. Can you explain on High performance computing ? I can see only Julia listed for it, not even C ? Concerning OCaml, the computer language shootout page has it almost as fast as C in a lot of benchmarks, but this can be subject to discussion.

    Talking of something else than OCaml, see Lisp that has meta programming, multiple dispatch which are not listed in your articles.

    • primus

      Thanks for your comments. Admittedly, this analysis was a little hasty as I am have been trying to ingest a lot of information in a very short time period.

      I realize the margins for omissions and errors have been large, and I will therefore revisit my post with corrections soon.

      Thank you, again.

  • Karsten

    honestly? High-Performance Computing is NOT done in Julia. All – and I mean all – HPC is done in either Fortran or C /C++. Any Cluster-Admin will kick you off the system if you ask for an installation of some other prog. language (remember, these things cost millions -any single CPU-cycle counts and is protocolled in € $ £ and ¥.

    • primus

      You bring up a valid point. I will revise.

  • kissmd

    just to start the flame war:
    as a java developer i use java (language and vm) in may daily work as
    “aspect oriented, functional, imperative, object-oriented, reflective, prototype-based, event-driven, generic, procedural, meta, lazy evaluation, structured”
    in fields of
    “application, general, web, scripting, client side, business, server-side, education, ?any?, text processing, web application”

    i dont care if it was intended to be so or not, nor if it requires an external library or not. but java (as language and as vm) is able to do all these things.

    not to mention oip, orm, tdd, bdd, maven and many other great things.

    i think the seniors of other languages could point out the same mistakes in your tables.

    • primus

      flame on. I certainly am in no position to disagree with anything you said.

      Thanks for the input.

  • anon

    You need to fact check your list of lazy evaluation supporting languages; your spreadsheet is wrong. It’s probably true that Haskell is the only language in your list that has that as default behavior on your spreadsheet but C#, for example, absolutely supports it.

    • primus

      I did not know that. Thanks.

  • Isaac Gouy

    >>Trivial and academic pursuits aside, the questions for choosing programming languages…<>Size(B): Corresponds to the average compiled size of code utilized to run task.<>Speed vs Memory vs Expressiveness<<

    The benchmarks game does not provide 3 independent measurements.

    Those measurements provide a single independent measurement (program elapsed time). Memory use and source code size are secondary dependent dimensions — because slower programs are arbitrarily replaced by faster programs in the dataset; and because the programs are shown in elapsed time order, program contributors optimise for program speed rather than space (both memory usage and source code size).

  • Isaac Gouy

    1) “Trivial and academic pursuits aside, the questions for choosing programming languages…”

    Trivial and academic pursuits aside, isn’t the question that matters — Which programming language will provide most (monetary) return on the investment I make in learning the language?

    2) “Size(B): Corresponds to the average compiled size of code utilized to run task.”

    No it doesn’t —

    3) “Speed vs Memory vs Expressiveness”

    The benchmarks game does not provide 3 independent measurements.

    Those measurements provide a single independent measurement (program elapsed time). Memory use and source code size are secondary dependent dimensions — because slower programs are arbitrarily replaced by faster programs in the dataset; and because the programs are shown in elapsed time order, program contributors optimise for program speed rather than space (both memory usage and source code size).

    • primus

      1. I have to agree. Anticipated monetary reward is often the deciding factor. I, however, am writing from the perspective of a non-programmer. I don’t get paid for writing code. I wrote this from the perspective of an analyst, and profit most from doing the most (accurate) work in the shortest amount of time.

      2. I stand corrected. Size corresponds to the “size of compressed source code instead of lines of code.”

      3. That’s a good point about one of the ways in which benchmarks can be biased. It’s kind of like Heisenberg’s uncertainty principle (although that’s maybe a stretch)… you distort observations by nature of trying to observe. Benchmarks are optimized, and therefore often fail to provide a fair and balanced understanding of a how a language performs in its day-to-day usage.

  • Wow, thiѕ post іs fastidious, mу ѕiѕtеr is anаlyzing such things,
    thus I am going to tеll hеr.

  • I’m actually exploring Python programming language. It’s my very first time dealing with programming. My first impression is: seems that most people assume that one must first learn the programming language in order to, then, think whatever program; or, better, that if one doesn’t know a computer language, one is unable to think a program. That seems absolutely false; one doesn’t need to learn Chinese in order to be able to think the stuff that’s going to be said then in Chinese. So natural language can be used to think and express any program one could think, of course not the thought nor its expression will be accurate enough to be run by a computer until it’s written in the proper computer language, but that’s another story. Since programming language seems to imply just certain restrictions over natural language, more than selecting the language that best fit my hypothetical requirements, could you point me somewhere I can be told about those specific restrictions first, in order to be able to use my natural languages skills to think “as if” in programming language from the very beginning? I know the moment will arrive, and maybe I’ll end up (or not) using a programming language not just to express but also to think all the thought in the exact terms that the thought must be expressed, but, in the meantime, I would like to feel (if what I’ve been saying is True) that I’ve already have the ability to think whatever is necessary to design any program, that learning a computer language is like learning a way to translate my own thought, and not a must learn to build any particular kind of brains that I don’t have yet.

    Is it possible to answer my question in plain natural language?
    Thanks in advance!