Syntax Matters
One of my coworkers, Scott, recently pointed me towards Jacob Kaplan–Moss’s comments on programming languages and thought. In “Syntactic Sugar”, Jacob addresses the canard that “all Turing complete language differ solely on syntactic sugar.” He first concedes that this is technically true, in terms of reduction to machine instructions and register manipulation. At the same time, he says, this view ignores the important effect qualitative differences in the syntactic structure of different programming languages have on the way we as programmers solve problems. In support of this, he introduces the Sapir–Whorf hypothesis from linguistics, which states that, rather than simply being a vehicle for thought, language in fact determines the limits of what is thinkable. He argues that this applies equally to programming languages, and concludes that “we’ll always be more productive in a language that promotes a type of thought with which we’re already familiar.”
Jacob’s initial concession is meant to let him get straight to the point: syntax matters, regardless of whether that syntax is purely “sugar” from the compiler writer’s point of view or not. You could go ahead and look at vocabulary (standard libraries) as well as semantics, but I’d like to look a bit more closely at Jacob’s argument and conclusions.
First off, let me say that I agree with what I see as the most important point of Jacob’s article: Syntax does matter. Unfortunately, I have to disagree with how he gets to that point and the conclusion he draws from it.
Throughout the article hides the assumption that a programming language is a Turing complete language. I believe this definition is overly restrictive. Pretty much any programming language you’ll pick up is Turing complete, but that’s not a necessity. TeX was originally not intended to be Turing complete; that it ended up so was due partly to lobbying by Guy L. Steele and partly to necessity (typesetting is not an easy problem!). Because it is Turing complete, you can (very painfully) abuse it to do things it was never meant to do. But even were it not, it would still have been a useful language for typesetting. I haven’t looked at other typesetting languages, such as eqn, roff, and pic, but it’s likely they were not Turing complete. These languages are used to program how a device should layout and style text. They might also allow you to define and apply function-macros. Maybe you’d want to call these markup languages and not programming languages, but that’s perhaps because you have defined programming language to require Turing completeness.
I also don’t think I can accept his initial concession that all Turing complete languages are the same when reduced to the level of the machine. Even Turing complete languages differ much more fundamentally than in syntactic sugar alone. The very ideas of computation that Prolog, Haskell, and C (or assembler) bring to the table are fundamentally different. That these ideas are basically equivalent comes down to the Church–Turing thesis.
At the same time, reduction to CPU or machine instructions is an insufficient reduction to establish equivalence. Even for the same machine, different compilers can produce different machine code given the same source. Even a single compiler can produce different machine code for the same source – this is why we have switches like -O[0..3] and -Osize for GCC. Further, all machine codes are not alike. Look at how x86 has been extended to accommodate the move from 16-bit to 32-bit computing (one very visible example: in the assembly language, a bunch of registers go from names like AX to EAX, where E stands for “extended”). There’s also the difference between RISC versus CISC instruction sets.
So we can extend Jacob’s claim: not only does syntax matters, but differences in syntax can even be caused by technically significant differences between programming languages. For the same reasons, though, I can’t embrace Jacob’s ultimate conclusion that, in light of the Sapir–Whorf hypothesis, “we’ll always be more productive in a language that promotes a type of thought with which we’re already familiar.”
Jacob sees programming languages as influencing programmer productivity. I would like to suggest a further programming language parallel of Sapir–Whorf. If you look at the similarities between the von Neumann machine and “von Neumann languages” like FORTRAN, C, and the bulk of languages widely deployed in computing’s brief history, you’ll start to think that hardware and languages influence each other, and possibly not for the best. (See “Can Programming Be Liberated from the von Neumann Style?”, an address by one of the creators of FORTRAN, for more on the limitations introduced by this style.)
Hardware influences the programming languages available to us as programmers. The type of algorithmic thought we’re accustomed to will then be determined by the programming languages we are most familiar with, so that hardware transitively determines our problem-solving approach. When we add this hardware–language parallel to the mix, hardware becomes, through historic accident, the driving factor behind programmer productivity (or the lack thereof).
Jacob’s conclusion that familiarity with a language’s “type of thought” guarantees the highest programmer productivity relies on a fundamental equality of languages being skewed in terms of productivity by each language’s similarity to our problem solving approach. But there are languages rooted in types of thought that might provide sufficient increases in productivity to be worth the trouble of learning to think a bit differently. That’s what Jane Street Capital is betting on in its use of Objective Caml in preference to any other language. (See Wadler’s brief remarks on a paper discussing this, “Caml Trading: Experiences with Functional Programming on Wall Street”. I don’t know where I read this, but I also recall something about it taking a company about 1–2 weeks to retrain Java/C++ programmers as (here my memory grows fuzzier) OCaml/Haskell/Erlang programmers.) That’s what the computer science community as a whole bet on when it made the move from navigational databases to relational databases. People still have trouble grokking the relational approach, but we’ve made the move nevertheless, as working with relational databases is much more productive in many cases than working with navigational databases.
Just because you’re most comfortable working with a language shouldn’t stop you from taking a long, hard look at what else is lurking in the wings and whether you might be able to be much more productive with an utterly different sort of language. If nothing else, the experience will be broadening. Jacob’s been looking into Scheme – what have you been doing?


5 Comments
Just a nit: the *roff languages were indeed Turning complete, with variables, assignments and loops.
The claim that “The very ideas of computation that Prolog, Haskell, and C (or assembler) bring to the table are fundamentally different. That these ideas are basically equivalent comes down to the Church–Turing thesis.” is technically incorrect; it indicates misunderstanding of both Turing-completeness and the Church-Turing thesis.
The fundamental equivalence of all Turing-complete languages rests on the possibility of implementing a compiler (or interpreter) for any one in any of the others. Since I could (this is where you can detect my background in theory as I gloss over the hard work of the actual doing) implement a C compiler in Prolog or a Prolog interpreter in C, the languages are exactly equivalent. They do not bring fundamentally different computational ideas to the table, though they do allow human beings to express such ideas in profoundly different ways.
The Church-Turing thesis is unncessary to establish the equivalence of formal programming languages. It claims that our intuition about what counts as a computer program is isomorphic with what can be expressed in a Turing-complete programming language.
For more details, see the Wikipedia article on the subject: http://en.wikipedia.org/wiki/Church%27s_thesis
BTW, I do believe that syntax matters tremendously. A really good programmer will completely avoid the one-size-fits-all approach and will carefully choose what language to use to implement a solution to a problem.
I agree that the semantics of programming languages matter, even if they’re all just bits in the end (and ignoring any raised by questions quantum computing wrt the universality of the Turing model). Ideally, one should be able to use “the best language for the job,” with “job” being defined as any arbitrarily-small piece of code.
Although I have recently returned to Mac development (after nearly 20 years in Windows Land), and still bleed at least four of the old Apple logo’s six colors, please allow me to suggest that Microsoft has out-innovated Apple in this area (let the flames begin!).
When Microsoft’s .NET Runtime was still in alpha (1998), it was architected to support “any language.” However, Microsoft defined “any language” to include only those languages that included the word “Microsoft” in their names, e.g., Microsoft C, Microsoft FoxPro, Microsoft Visual Basic, etc. Oops.
From Microsoft Research, I organized a program (Project 7) to bring in a slew of grad students, where they implemented .NET-compatible versions of their professors’ programming languages (Haskell, Oberon, Scheme, Mercury, and many others).The Runtime only needed a couple of minor extensions to support these languages, and those extensions were added expeditiously (because its architects had actually done a very good job). Today, the .NET Runtime may not be able to support “any” language, if only because smart programmers could undoubtedly design a language that it couldn’t support, but…close.
This flexibility accelerates the process of bringing new features — previously restricted to a single language or language type — to all languages, via the .NET Runtime.
For example, Eiffel’s support for contracts is very nifty; Bertrand Meyer et al. are working with Microsoft to bring compiler- and runtime- enforcement of contracts to all languages. Likewise, working with SimonPJ and others in the Haskell community, Microsoft Research’s Erik Meijer et al. added deep support for functional programming to the Runtime, initially in the domain-specific F# language. This support is now exposed (for example) in Microsoft’s LINQ technology, and is poised to be an important tool in Microsoft’s cloud computing initiative.
Just as GUI development benefits from exploiting the design patterns enabled by the XCode/IB/Cocoa/Objective-C toolset, cloud computing benefits from exploiting the design patterns enabled by…a toolset that no one fully understands yet. By opening up its Runtime and IDE to novel languages and design patterns, Microsoft has made it easy for this as-yet unknown toolset to emerge first, best, and/or only on Windows.
However, the benefits of having a language-agnostic tool platform go well beyond cloud computing. They accelerate the rate of improvement, and that platform which accelerates fastest into the future eventually wins, even if it starts out behind.
Objective-C, leveraged by the XCode/IB/Cocoa/etc toolset, arguably makes Mac development more productive than Windows developers can be with any combination of Visual [Whatever] languages on the .NET Runtime *TODAY*. However, things change — and with the .NET Runtime, they are already changing very rapidly. Microsoft could catch up much faster than you might think. Having provided a platform on which third parties can innovate, all Microsoft needs to do is get out of their way (and then copy their best ideas into the .NET Runtime).
So, while I’m very happy to come back to the Mac after nearly 20 years in Windows Land, and I appreciate the productivity advantage Mac developers now have, I also note that Apple can’t afford to rest on its laurels (again). Else, sic gloria transit Mac-ee.
For whatever that’s worth…
— Jim
“we’ll always be more productive in a language that promotes a type of thought with which we’re already familiar.â€
That one hurt, a lot, when I read it. Yes, knowing a particular language when you are using said language will make you more productive, but it is foolish to believe that once you have acquired on type of thought you do not need any more. I had to learn how to program, I was not born with that ability. I have never seen developers more poor in their trade than those that define themselves by a language (for instance java programmer).
As a computer scientist/software engineer one should always learn more and that includes “types of thoughts”. I intend to learn more about any language I either find interesting or that would be required by the job I am performing. Challenging your thought patterns is an absolute must, and learning to express yourself in new meaningful ways will always make you a better software engineer.
A friend likes to point out that you should learn one new language per year. I think that he is fantastically correct!
Syntactic considerations have always had a major impact on what I think about a language, and how much I enjoy programming in it. My tastes run towards those with minimal punctuation and few brackets, such as python and haskell, as opposed to languages such as perl and ruby. Of course, those are just my tastes, and I don’t expect anyone to share them.
I’ve met most programming paradigms (I’m sure there some I haven’t met), and have found that the paradigm has made no difference to my effectiveness as a programmer.
So, my experience in programming neatly matches the fact that the Sapir-Whorf hypothesis has been thoroughly discredited in linguistics for over forty years.