Update 11/23/2020: The ultimate winner for my primary programming language was Racket.
The 2008 Programming Language Plan didn’t go as well as I hoped, so I’m regrouping for another go at it. I did make progress learning some Logo and teaching it to my daughters, and I worked through seven chapters of “Programming in Haskell” which was very enjoyable, but I also spent way too much time trying to decide which language(s) to learn without actually learning them.
I have now decided which languages I want to learn this year, so I figured I’d post this blog entry. In some respects, things haven’t changed much from last years plan, but my decisions are much less tentative which is encouraging. I’m glad to switch from information gathering to actually learning a few languages.
When I switched from C++ to Java in 1996 and noticed a large increase in productivity; however, it didn’t occur to me to consider whether switching from Java to another language might also give me a similar boost in productivity. The job demand for Java was high during the 10 years I used it, and I was getting paid for my time vs. what I produced, so the oversight wasn’t too costly.
When I switched from Java to Ruby in 2006 I experienced a comparable, if not greater, boost in productivity as I had with the switch from C++ to Java. This time I considered the effect of programming language choice on productivity more carefully and began to wonder about the optimal programming language for me. As a small business owner, my primary consideration is productivity, not popularity or the interchangeableness of programmers.
I don’t think a perfect programming language exists in general, but I think there is an optimal language for me given my particular circumstances, the problems I want to solve, the type of software I want to develop, my way of thinking, my aesthetic tastes, etc.
There is a cost to research programming languages to determine the optimal one, and there is a cost to switch programming languages, so the benefit of a new programming language needs to exceed those costs.
Additionally, a significant catch–22 exists in that to truly determine if a language is optimal, one must reach a level of proficiency with the language. There isn’t enough time to learn all of the candidate languages, so some filtering mechanism must be used first to narrow the choices to a reasonably small set. This filtering mechanism is theoretical by nature, but I think the subtle practicalities of a language have a significant effect on productivity.
I have a long term perspective for this task, so I don’t mind investing time researching programming languages, and I also don’t mind if I need to develop/acquire supporting libraries before being ultimately more productive than I am currently with Ruby and Rails.
I briefly entertained the idea of going about this research in a more systematic, scientific way. That might be a reasonable approach, but due to the following:
- My laziness
- The high degree of subjectivity in programming language choice
- The lack of consensus among programming language researchers
I ended up with a fairly ad-hoc approach involving examining the following areas and trying to absorb enough information to formulate a plan:
Programming language efficiency is becoming increasingly important to me as Moore’s law loses steam, and power & cooling issues become more prominent.
On the one hand, Ruby is near the bottom of the pack with respect to efficiency, but the productivity has been outstanding, and at the volume of transactions I’ve needed to deliver thus far, performance hasn’t been a problem.
On the other hand, if programming languages exist (and I believe they do) that have similar or greater power than Ruby but are compiled instead of interpreted, that would be an advantage.
Benchmarks are notoriously controversial with respect to the degree in which they predict performance, but I don’t think they’re irrelevant. One popular benchmark site is: Programming Language Shootout. I also created some micro-benchmarks of my own to test performance.
One negative result of Ruby being inefficient is the disparity in performance of code written in Ruby vs. library code, or extensions, written in C. This creates counter-intuitive scenarios where a piece of code that appears less efficient is actually more efficient because of the use of built-in code implemented in C. I don’t like thinking in those terms; I would much prefer that user written code in the language is much closer to the efficiency of built-in library code.
With the flattening of CPU MHz and proliferation of CPU cores, I think concurrency may continue to grow in importance. Although I develop mainly server side web applications which can take advantage of multiple cores by virtue of having multiple independent processes, I would prefer to have better concurrency mechanisms in the language/libraries directly.
I think I first heard joy used, in the context of programming languages, in the Ruby community – probably from Matz himself. I have to agree that programming in Ruby has been more joyful than previous programming languages.
I’m not sure exactly why this is, but I expect it has something to do with the effectiveness and productivity of Ruby, but it may be helped by the incredibly friendly Ruby community.
My preference is for a programming language to minimize arbitrariness and to maximize orthogonality. In other words, I would prefer the language to have a minimal set of core concepts/axioms/operators/etc. that are built upon systematically.
Whether my optimal language is mainstream or not is irrelevant to me, so I don’t need the programming language community to be large (and in fact, being too large is a detriment), but I do think it should be active enough that there are people available to help answer questions, write libraries, maintain/improve compilers, debuggers etc.
To this end, I spent time on various usenet groups, IRC channels and blogs. Occasionally asking questions, but mostly observing the dialog and interaction among the community members.
What educational materials are available?
I tend to prefer learning from books, so searching Amazon to see what books are available, how well they’re received, etc. was helpful. Although I prefer books typically, in the exploratory stages, it’s cheaper to go through online materials, so searching the web for free PDFs was useful. The existence of a few good texts is also an indication of the vitality of community.
Ultimately, I’m after the most productive language for me; however, I think productivity is the factor that requires the most proficiency with a language to judge, so it was the most difficult factor to research prior to learning a language. I was limited to anecdotal stories, case studies, personal testimonies, etc.
I prefer open source licensing because I think programming languages with proprietary licensing are more likely to die.
The Final Candidates
I began with Ruby as the point of reference irrespective of Rails and other libraries. Even though Rails is an important factor in my current productivity, since I’m taking a long term view, I didn’t want to exclude a fantastic language simply because it’s lacking something that Ruby was also lacking N years ago.
Due to the cost of researching, learning and switching to a new programming language, I only considered languages that had the potential of offering a significant improvement in one or more areas without losing too much in other areas.
The candidates I eventually selected fell into two groups. Both groups have strong functional capabilities, good efficiency, and long, successful track records. I believe that even the best programming language designers make serious mistakes which can only be identified with the hindsight of years of use. It’s possible that someone is about to release a brand new language that has the potential to be the most productive for me personally; however, I’m not willing to take the risk to learn it.
The Lisp Family
Lisp has a very long track record of success and adaptability. In fact, if I was forced to program in a single programming language from now on, I would probably choose a Lisp since I think it would have the greatest likelihood of being able to adapt.
The Lisp family has dynamic typing which I’ve grown to love with Ruby, but most also allow type declarations for efficiency. Lisp also appears to have a more fundamental nature than most languages. I’ve heard it said that Lisp was more discovered than invented.
I first became interested in Lisp when I learned that Ruby was influenced by it. My interest was reinforced by some of Paul Graham’s essays & books. I like the exploratory and dynamic nature of developing Lisp – this is mostly from reading comments of others, but I’ve tasted a small part of this when evaluating Lisp code in Emacs and having it be available immediately.
Logo is first on the list simply because it’s both a Lisp and a great language for teaching children how to program, so I can kill two birds with one stone.
Scheme is next because it’s a natural sequel to Logo and I still want to work through “The Structure and Interpretation of Computer Programs”. The fact that Paul Graham chose mzcheme to create his Arc language is a good “letter of recommendation”. Scheme feels the most fundamental, simple & clean thus far.
Common Lisp is after Scheme due to its eminent practicality and completeness. It has plenty of warts, but also plenty of power and functionality. It’s been called a great, big, ball of mud – but in a good way.
Lastly, is Clojure. It’s last in the Lisp family because I want to learn Scheme & Common Lisp first so I’ll be better equipped to judge Clojure. This will also allow more time for Clojure to mature. Clojure has a focus on functional programming & concurrency that is symbiotic with the Java platform. The latter provides a quick start and access to Java libraries, the JVM infrastructure, etc., but my preference would be to not be dependent on the JVM in the long run. I’ll withhold judgment until I’ve learned it and used it for a while.
The ML Family
I’m least familiar with the ML family and with functional programming in general. I’ve spent most of my career studying and using imperative, object-oriented programming languages.
I think the ML family is worth studying because:
- Functional programming may be beneficial with respect to concurrency.
- Prog. Lang. researchers seem to be enamored with ML family.
- There are enough anecdotal testimonies of productivity to warrant further study.
Standard ML is an important functional language that differs from Haskell in that it’s impure, i.e. it allows side effects, and it’s strict, i.e. not lazy. It shares Hindly-Milner static typing with Haskell. The community seems rather tiny, and I expect that if I go with a static typed language it will likely be Haskell, but I wanted to learn Standard ML first because of its historical importance and to be able to compare an impure/strict language with a pure/nonstrict language.
Haskell is probably the most different programming language from what I’m used to. This, in and of itself, has some advantages with respect to gaining new perspectives and ideas. In some ways, it’s a language that has taken things to extremes with respect to functional purity and laziness.
The community is very active. It offers a great compiler (GHC), software transactional memory, a decent base of libraries, etc.
At this early stage, I’m skeptical of static typing, functional purity and laziness, so becoming proficient in Haskell is a great opportunity to be able to determine how I feel about those.
Rather than go through the candidates sequentially, I’m going to try and make progress on two tracks concurrently to allow me to compare concepts from both families:
|ML Family||Lisp Family|
I’m curious to find out how I feel about these languages after I’ve achieved some skill with them, but I think becoming proficient in the Lisp and ML families will be time well spent. At minimum, I’ll be better equipped to compare other languages.