The Best Programming Language (or How to Stop Worrying and Love the Code)

« More entries

EDIT: This post has been translated to Japanese.

Every once in a while, someone, somewhere, decides it’s time to write yet another post on what’s the best programming language, the mighty properties of a forgotten language, or the new language that does it right. So my time has come. Finally, I get to say what I think about programming languages.

First of all, a disclaimer: unless you’ve developed in 30+ languages, and suffered the code of others in all (or most) of them, you can’t really be objective. So yes, I’m biased. Like most of the people writing about this topic. Actually, I believe that this topic becomes absurd as soon as you are well-versed in many languages.

Before you read on…

This article is highly opinionated. Not everything I wrote here back then is a fact, but rather my experience at that point. After realizing that there is actual interest in real data and technical comparisons between languages, I’ve decided to conduct a deeper research. I’ll make a whitepaper with a deep analysis of the most relevant languages for you. If you are interested in this, please subscribe here to get a notification when the whitepaper is released.

TL;DR: The Great Languages

I hereby declare these languages to be The Great Languages within the realms of my blog.

  • Assembly: the language of the machine.
  • C: the systems language.
  • Javascript: the language of the web.
  • Scheme: the lightweight, embeddable and extremely flexible language that compiles to both C and Javascript.

Most of the code examples are from Rosetta Code.

The Reasonable languages

I don’t call these reasonable languages because I think they are the best languages. They just are the languages people use most nowadays, which makes them eligible for production software. Of course, you can bypass this argument and just go for gut decisions. In that case, go to the next section.

Ada

I’ve always been curious about the idea of designing a language around memory safety. That makes sense for applications in real-time operating systems and critical systems in general. Probably if you are considering using this language you don’t need to read this, and you come from a highly specialized background. This is one of the languages that you use once you know what you are doing, and then you don’t have many options either. Some bits of Ada:

   function Best_Shuffle(S: String) return String is
      T: String(S'Range) := S;
      Tmp: Character;
   begin
      for I in S'Range loop
         for J in S'Range loop
            if I /= J and S(I) /= T(J) and S(J) /= T(I) then
               Tmp  := T(I);
               T(I) := T(J);
               T(J) := Tmp;
            end if;
         end loop;
      end loop;
      return T;
   end Best_Shuffle;

It looks safe, right? ;)

Bourne (Again) Shell

I always think: do I really need to write this Linux script in a shell language? Is it really necessary? It doesn’t matter if you don’t write your scripts in shell, because eventually you’ll deal with one of these scripts face to face, and you’ll wonder how they did it in the Bare Metal Age, pre-stackoverflow. Anyway, with the right book, you’ll start thinking that the language just needs some make-up (and consistency). There is nothing amazing about this language, nothing that will expand your mind or make you more productive, or that justifies it from the business point of view. It is just pervasive in the *nix world. Nevertheless, it’s a must for system administration, and it isn’t as bad as it looks. It’s a bit like Javascript, you need to know the good practices more than with other languages.

When would I use Unix Shell?

  • OSX/Linux/POSIX system administration
  • For task automatization
  • To unlock command-line superpowers

Some Bourne Shell code. Enjoy those boolean expressions!

#!/usr/bin/env sh

l="1"
while [ "$l" -le 5 ]
  do
  m="1"
  while [ "$m" -le "$l" ]
    do
    printf "*"
    m=`expr "$m" + 1`
  done
  echo
  l=`expr "$l" + 1`
done

C

Well, you have to respect C, even if you don’t like it. It’s arguably one of The Great Languages. The language that programs machine reality (not models of). It’s the father of UNIX, all the languages of the capital C, and the lingua franca of systems development. It’s been battle-tested, time-tested and hype-tested. The plethora of tools available for developing, debugging, profiling and supporting C development make it for all its defects as a language (not so many, in my opinion). It’s a language that really achieved its purpose: become a general-purpose Assembly language for every processor. Nowadays, it is the de-facto Assembly for even the strangest architecture, and it has become very hard to make better hand-crafted code than that generated by C compilers.

It is thus a powerful tool, but one that needs to be mastered. The language shows no mercy, and you always need to know what you are doing. That is what makes C the language for understanding the machine. There is beauty in this, and there is a practical side too: there are things that just can’t be done without the kind of low-level that C provides. C programmers must understand very well what they are doing, leading to very solid software in the long run. If there is something that could debunk C is a low-level language with great support for concurrency. Or maybe a mythical language with the properties of Haskell and the pervasiveness of C.

Some C from the Linux Kernel:

int next_pidmap(struct pid_namespace *pid_ns, unsigned int last)
{
    int offset;
    struct pidmap *map, *end;

    if (last >= PID_MAX_LIMIT)
        return -1;

    offset = (last + 1) & BITS_PER_PAGE_MASK;
   map = &pid_ns->pidmap[(last + 1)/BITS_PER_PAGE];
   end = &pid_ns->pidmap[PIDMAP_ENTRIES];
   for (; map < end; map++, offset = 0) {
       if (unlikely(!map->page))
           continue;
       offset = find_next_bit((map)->page, BITS_PER_PAGE, offset);
       if (offset < BITS_PER_PAGE)
           return mk_pid(pid_ns, map, offset);
   }
   return -1;
}

C++

A monster. It was my first language, and I didn’t really understand how it was screwing my productivity and limiting my skills until I tried many others. The bad reputation of C++ is promoted by some well-known programmers, and I agree completely. C++ seems as if Bjarne Stoustrup took every single feature he could think of and added it to C. The cognitive load it imposes might make you more than 80% less productive. Think of it this way: you have a brain of X capacity, and that capacity is limited, doesn’t matter how much capacity you have, and you want to leave as much as possible of it for the important things. The wise thing to do would be to reduce the amount of brain power used for the language per se, and use the most of that brain for solving the problem and encoding an algorithm. If the language is complex, no matter how smart you are, you’ll need to use more of your brain for the syntax and the semantics of the language and less to efficiently projecting your ideas onto code.

I think C++ is the quintessential example of too much complexity for not that much gain. I agree, building large programs in C is difficult (but arguably an option, look at the Linux Kernel). Go, Rust and D are better languages by all measures, except for the fact that C++ is what the world actually uses.

This is a nice example of good C++ using templates. C++ works looks much more comprehensible in user code like this, rather than template/classes definitions.

#include <fstream>
#include <string>
#include <iostream>

int main( int argc , char** argv )
{
    int linecount = 0;
    std::string line;
    std::ifstream infile( argv[ 1 ] );
    if( infile )
    {
        while( getline( infile , line ) )
        {
            std::cout << linecount << ": " << line << '\n';
            linecount++;
        }
    }
    infile.close();
    return 0;
}

And then some template code, a very simple example (which tends to grow naturally in an awful way).

namespace rosettacode
{
  template<typename T> class queue
  {
  public:
    queue();
    ~queue();
    void push(T const& t);
    T pop();
    bool empty();
  private:
    void drop();
    struct node;
    node* head;
    node* tail;
  };

  template<typename T> struct queue<T>::node
  {
    T data;
    node* next;
    node(T const& t): data(t), next(0) {}
  };

  template<typename T>
   queue<T>::queue():
    head(0)
  {
  }

  template<typename T>
   inline void queue<T>::drop()
  {
    node* n = head;
    head = head->next;
    delete n;
  }

  template<typename T>
   queue<T>::~queue()
  {
    while (!empty())
      drop();
  }

  template<typename T>
   void queue<T>::push(T const& t)
  {
    node*& next = head? tail->next : head;
    next = new node(t);
    tail = next;
  }

  template<typename T>
   T queue<T>::pop()
  {
    T tmp = head->data;
    drop();
    return tmp;
  }

  template<typename T>
   bool queue<T>::empty()
  {
    return head == 0;
  }
}

C#

Enterprise language that aims at reducing any kind of programmer creativity that might hinder its replaceability in any large organization. Object-oriented, statically typed, verbose, with heavy libraries and lots of boilerplate. You can see Microsoft’s hand behind this creation. But don’t get me wrong, is not a bad language. It just isn’t sexy, which precisely is what Microsoft wanted in first place. At least, is a radical improvement when compared with Visual Basic. I would use it for:

  • Windows development.
  • Game development (well, mostly because Microsoft forces developers, but I would still prefer good ol’ C/C++).
  • There are huge things going on in this language: Unity3D, Xamarin, .NET, XNA.

Here’s some code.

using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;

class Program
{
    static SortedDictionary<TItem, int> GetFrequencies<TItem>(IEnumerable<TItem> items)
    {
        var dictionary = new SortedDictionary<TItem, int>();
        foreach (var item in items)
        {
            if (dictionary.ContainsKey(item))
            {
                dictionary[item]++;
            }
            else
            {
                dictionary[item] = 1;
            }
        }
        return dictionary;
    }

    static void Main(string[] arguments)
    {
        var file = arguments.FirstOrDefault();
        if (File.Exists(file))
        {
            var text = File.ReadAllText(file);
            foreach (var entry in GetFrequencies(text))
            {
                Console.WriteLine("{0}: {1}", entry.Key, entry.Value);
            }
        }
    }
}

Wouldn’t you say it resembles Java?

Objective-C

I have a much better opinion of Objective-C than of C++ (and C#). It’s syntactically ugly, but I like it as a language. It’s got a great set of libraries based on NextStep, with the plus of being a real improvement upon C, without growing too much out of control and bringing ambiguities in keywords with its parent language. As I said, it’s a bit ugly and difficult to read, especially when nesting functions, but definitely its beauty resides in its conceptual approach, not in its syntax. See this nested calls:

char bytes[] = "some data";
NSString *string = [[NSString alloc] initWithBytes:bytes length:9 encoding:NSASCIIStringEncoding];

This is beautiful code for a son of C language, making use of Objective-C’s so-called blocks.

#import <Foundation/Foundation.h>

typedef NSArray *(^SOfN)(id);

SOfN s_of_n_creator(int n) {
  NSMutableArray *sample = [[NSMutableArray alloc] initWithCapacity:n];
  __block int i = 0;
  return ^(id item) {
    i++;
    if (i <= n) {
      [sample addObject:item];
    } else if (rand() % i < n) {
      sample[rand() % n] = item;
    }
    return sample;
  };
}

int main(int argc, const char *argv[]) {
  @autoreleasepool {

    NSCountedSet *bin = [[NSCountedSet alloc] init];
    for (int trial = 0; trial < 100000; trial++) {
      SOfN s_of_n = s_of_n_creator(3);
      NSArray *sample;
      for (int i = 0; i < 10; i++) {
        sample = s_of_n(@(i));
      }
      [bin addObjectsFromArray:sample];
    }
    NSLog(@"%@", bin);

  }
  return 0;
}

Clojure

Being a Scheme programmer I have respect for Clojure: it’s a so-called modern Lisp, with some unique features. I’d say Clojure’s strong points are Java interoperability and concurrency utilities in the core language. It’s a sibling of Scala, but differs in their flavor: lisp vs. hybrid OOP/functional, making Clojure less popular due to the excess of parenthesis. Choosing one of these two for a project it’s a matter of tastes, because neither are proven technologies with a long track record of successful production applications, as compared with Java or PHP, although they both stand on the shoulders of JVM. Another thing to take into consideration for any JVM-base language is the startup time of the virtual machine: it doesn’t seem like a very lightweight solution for small tasks. These are the situations where I would use Clojure:

  • Web development. There are good options for this, and the Clojure community seems very active in this area.
  • When you want to use the JVM technology without the Java thing. Both programmer happiness and productivity will improve.
  • Exploratory programming, that could grow into production code. This is actually an area where its Lisp nature really shines, but Clojure relies on the Java stack, exposing many production code to it.
  • Android development? Android development GUI development model relies heavily on class inheritance (meaning that you don’t actually use it as a plug-in library, it forces you to follow a certain structure). It can be done, but it certainly isn’t as natural as direct Java inheritance.

Some classical Clojure code:

(defn divides? [k n] (= (rem n k) 0))

(defn prime? [n]
  (if (< n 2)
    false
    (empty? (filter #(divides? % n) (take-while #(<= (* % %) n) (range 2 n))))))

And a simple queue definition in the lisp way.

(defn make-queue []
  (atom []))

(defn enqueue [q x]
  (swap! q conj x))

(defn dequeue [q]
  (if (seq @q)
    (let [x (first @q)]
      (swap! q subvec 1)
      x)
    (throw (IllegalStateException. "Can't pop an empty queue."))))

(defn queue-empty? [q]
  (empty? @q))

D

I used to love D. D is like C++ done right. D1 felt like a low-level-oriented Python. Like a pythonized C or something like that. It’s awesome: you feel development speed, focusing on the algorithms and not the language, but you don’t sacrifice low-level control when you need it. D2 brought a lot more of the complexity of C++, with the innovative touch of Andrei Alexandrescu. That made part of the community unhappy, albeit D2’s focus on concurrency. D2 is not a clean language any more, but feels more like an experimental language with lots of untested features. I like it though, but I think it’s features pale in comparison with C++’s pervasiveness (once you have a more complex language). And also I think Go took the place that was once D’s destiny. Walter and Andrei can’t compete with Google, even if they can move faster and implement really cool things in the language. You can like D (as I sort of do), but I don’t see a bright future for it. Just stick with C++ or go to Go for better native concurrency support. So, when would I use D?

  • For developing a project from scratch, being able to interface C and to some extent, C++. You have to think in advance what those interfaces are going to be like, though. For instance, I wouldn’t recommend it you need to use a C++ GUI library, because that normally means dealing with C++ inheritance from within and that will throw all the advantages away. Just do this if you need C++ for a plug-in library (creating objects and using its functions, but no templating or C++ inheritance).
  • If you need low-level programming with fast binaries. Again, doing your own thing, like a standalone program.
  • If you want better native support for concurrency in the language.

Let’s see some idiomatic D2, with pure functions, and immutable declarations.

uint grayEncode(in uint n) pure nothrow {
    return n ^ (n >> 1);
}

uint grayDecode(uint n) pure nothrow {
    auto p = n;
    while (n >>= 1)
        p ^= n;
    return p;
}

void main() {
    import std.stdio;

    " N     N2      enc     dec2 dec".writeln;
    foreach (immutable n; 0 .. 32) {
        immutable g = n.grayEncode;
        immutable d = g.grayDecode;
        writefln("%2d: %5b => %5b => %5b: %2d", n, n, g, d, d);
        assert(d == n);
    }
}

The max element of a list.

[9, 4, 3, 8, 5].reduce!max.writeln;

It is definitely more expressive and a cleaner language than C++, by far.

Erlang

This is a very specific-purpose language. Erlang’s web page describes it very clearly: […] build massively scalable soft real-time systems with requirements on high availability. Some of its uses are in telecoms, banking, e-commerce, computer telephony and instant messaging. Erlang’s runtime system has built-in support for concurrency, distribution and fault tolerance. Erlang has been proven for, and its behind some very demanding applications such as WhatsApp. The code itself feels very functional, and its syntax is clean and very readable.

Take a look at the code for a simple concurrent program:

-module(hw).
-export([start/0]).

start() ->
   [ spawn(fun() ->  say(self(), X) end) || X <- ['Enjoy', 'Rosetta', 'Code'] ],
   wait(2),
   ok.

say(Pid,Str) ->
   io:fwrite("~s~n",[Str]),
   Pid ! done.

wait(N) ->
   receive
       done -> case N of
           0 -> 0;
           _N -> wait(N-1)
       end
   end.

Go

I haven’t used this personally. Yet. But it’s clear that this is Google’s take on making a C with the good parts of C++ and better than both in its concurrency support. It has better features than C++, and it is way simpler. It has no unsafe pointer arithmetic, closures and first-class functions, and garbage collection. Go might become the server language in the future. So, when would I try Go?

  • For server applications that need very high reliability and performance. This includes web apps.
  • For highly-concurrent code that requires low-level control (otherwise, I’d stick to Erlang).

Go concurrent code:

package main

import (
    "fmt"
    "math/rand"
    "time"
)

func main() {
    words := []string{"Enjoy", "Rosetta", "Code"}
    rand.Seed(time.Now().UnixNano())
    q := make(chan string)
    for _, w := range words {
        go func(w string) {
            time.Sleep(time.Duration(rand.Int63n(1e9)))
            q <- w
        }(w)
    }
    for i := 0; i < len(words); i++ {
        fmt.Println(<-q)
    }
}

Haskell

This language truly feels as a more advanced thinking tool than the others in this list. It has libraries for almost any need and it has a hard-core community. Arguably it’s a language with a high barrier of entry. It will expand your mind, and surround you with some of the brightest minds in the programming languages communities, in my opinion.

I think Haskell is well worth learning, even if you don’t build any real program with it. Being a relatively obscure language, I chose to classify it as reasonable since it is actually used in several areas, and especially in the financial industry. Haskell’s code tends to be very compact and expressive, albeit a bit abstract, in the sense that you need lots of functions that are actually conceptual operations rather than steps of a process. I personally don’t like its syntax (I think it has way too much syntax), but at least it serves a purpose and doesn’t feel like clutter (I’m looking at you Perl!). This language feels beautiful and coherent. Take a look by yourself:

binarySearch :: Integral a => (a -> Ordering) -> (a, a) -> Maybe a
binarySearch p (low,high)
  | high < low = Nothing
  | otherwise =
      let mid = (low + high) `div` 2 in
      case p mid of
        LT -> binarySearch p (low, mid-1)
        GT -> binarySearch p (mid+1, high)
        EQ -> Just mid

Java

The same as C#, but for the Java Virtual Machine. Was there first (in fact C# copied it), and it’s sort of “the standard” object-oriented language in the industry. It’s used for everything, from web apps to games. Almost everything except embedded device software, and perhaps high performance parallel computation software. It serves as the foundation for many other languages (specifically its virtual machine). Take a look at Processing for an interesting project, where a wrapper language (just sugar-coated Java) is used for education and digital art. When would I personally recommend you Java?

  • Mostly when you want to access a very large pool of developers and knowledge base, i.e. You want the software to be maintained by someone else.
  • When you need a multiplatform virtual machine present in as many devices as possible.

Java 7 code example, reading a file:

import java.util.List;
import java.nio.charset.Charset;
import java.nio.file.*;

public class ReadAll {
    public static List<String> readAllLines(String filesname){
        Path file = Paths.get(filename);
        return Files.readAllLines(file, Charset.defaultCharset());
    }

   public static byte[] readAllBytes(String filename){
       Path file = Paths.get(filename);
       return Files.readAllBytes(file);
   }
}

I guess you’ve seen more Java code before, so I’m not going to bother you with a class definition.

Javascript

The lingua franca of the 2010’s, the language of the web. The funny thing is that while it was previously seen as a very defective and limited language, a more recent wave of programmers have shown the world that following a set of good practices and using various techniques, it actually turns out to be a great language. Especially if you take into account all the libraries and implementations that make up for Javascript’s design mistakes or missing features (such as a module system). Thanks to this, we even have Javascript for the server, which brought this beautiful symmetry backend/frontend to life, finally.

There is a lot of research and effort put into improving Javascript performance and derivative languages that compile to Javascript. This actually proves that community is one of the greatest (if not the greatest) assets a language could have. The funny thing is, you see myriads of libraries doing the same thing over and over, making it one of the most competitive arenas for a library developer. See examples as Grunt vs. Gulp, or the battalions of competing Javascript derivatives (Coffeescript, Typescript, Livescript…). It’s crazy out there.

The following code shows Javascript’s prototype-based classes and inheritance.

function Car(brand, weight) {
  this.brand = brand;
  this.weight = weight || 1000;
}
Car.prototype.getPrice = function() {
  return this.price;
}

function Truck(brand, size) {
  this.constructor(brand, 2000);
  this.size = size;
}
Truck.prototype = new Car;

var cars = [
  new Car("Mazda"),
  new Truck("Volvo", 2)
];

for (var i=0; i<cars.length; i++) {
    console.log(cars[i]);
    console.log("brand: "+cars[i].brand+". weight: "+cars[i].weight+"." + (( cars[i].hasOwnProperty('size') ) ? " size: "+cars[i].size : ""));
    console.log("Car: %s. Truck: %s\n", cars[i] instanceof Car, cars[i] instanceof Truck);
}

And this shows functional-style code using the Lo-dash library:

var characters = [
  { 'name': 'barney',  'age': 36 },
  { 'name': 'fred',    'age': 40 },
  { 'name': 'pebbles', 'age': 1 }
];

var youngest = _.chain(characters)
    .sortBy('age')
    .map(function(chr) { return chr.name + ' is ' + chr.age; })
    .first()
    .value();

I find it rather cool to mix these two styles easily, once you come to grips with Javascript’s particularities (yeah, like the this thingy).

OCaml

It’s sort of like Haskell, but it feels like more willing to bend to the programmer’s desires. When there is need, some compromises to its purity are made in benefit of easier solutions, for instance when the procedural/object-oriented approach seems to work best. There are companies using it, I guess just for this benefit over Haskell. Take a look at this little snippet:

let n_arrays_iter ~f = function
  | [] -> ()
  | x::xs as al ->
      let len = Array.length x in
      let b = List.for_all (fun a -> Array.length a = len) xs in
      if not b then invalid_arg "n_arrays_iter: arrays of different length";
      for i = 0 to pred len do
        let ai = List.map (fun a -> a.(i)) al in
        f ai
      done

Looks almost like Haskell, right? But then you have the imperative flavor in that for loop…

PHP

Don’t just assume PHP is horrible. Be a good spartan and inflict yourself the joy of PHP. The good thing is: if you enjoy programming in PHP, then you are a true programmer. And it’s the language of the cheap freelance work. When would I use PHP?

  • If you want to have the largest pool of web developers available.
  • That’s it, no other reason.

Pretty code in PHP. I hope you like dollars.

function hashJoin($table1, $index1, $table2, $index2) {
    foreach ($table1 as $s)
        $h[$s[$index1]][] = $s;
    foreach ($table2 as $r)
      foreach ($h[$r[$index2]] as $s)
        $result[] = array($s, $r);
    return $result;
}

$table1 = array(array(27, "Jonah"),
           array(18, "Popeye"),
           array(28, "Alan"));
$table2 = array(array("Jonah", "Whales"),
           array("Jonah", "Spiders"),
           array("Alan", "Ghosts"),
           array("Bob", "foo"));

foreach (hashJoin($table1, 1, $table2, 0) as $row)
    print_r($row);

Python

A pretty language.I definitely like its whitespace-based block structure: you don’t need ugly semicolons all the time. I like this so much that I tend to write my Javascript this way. But this is very much a matter of taste, and as a matter of fact is the very reason many people don’t like the language. It’s a clean language that tries to take the burden of the syntax out of you shoulders. While it is debatable that it succeeds at this, the language is definitely supported by a great community, that put the it in a very strong position when compared to its pal Ruby. It’s always hard to choose between these two languages, although Python seems more widespread, and a more sensible choice for a variety of fields and applications. When would I use Python?

  • Web development.
  • Scientific computing and data analysis.
  • System administration and tools.
  • Game/3d application scripting.
  • Cross-platform support.

Nice Python code:

from itertools import islice

def hamming2():
    '''\
    A text documenting this function (stripped)
    '''
    h = 1
    _h=[h]    # memoized
    multipliers  = (2, 3, 5)
    multindeces  = [0 for i in multipliers] # index into _h for multipliers
    multvalues   = [x * _h[i] for x,i in zip(multipliers, multindeces)]
    yield h
    while True:
        h = min(multvalues)
        _h.append(h)
        for (n,(v,x,i)) in enumerate(zip(multvalues, multipliers, multindeces)):
            if v == h:
                i += 1
                multindeces[n] = i
                multvalues[n]  = x * _h[i]
        # cap the memoization
        mini = min(multindeces)
        if mini >= 1000:
            del _h[:mini]
            multindeces = [i - mini for i in multindeces]
        #
        yield h

Ruby

Ruby on Rails. The single reason this language could ever be part of this list. Of course, nowadays it’s easy to see it in many other projects, but it all began with Rails. Before that, Ruby was an obscure programming language from Japan. This is a perfect example of how a killer app/framework spawned a great community which in turn made more killer apps/frameworks and made the language popular even though the place for this sort of language was supposedly taken.

One thing I’ve heard from many Ruby developers and I had experienced myself, is the actual joy that comes from using it. In other words, it’s the contrary of a frustrating language, although I don’t know if this is something from the language or Rails itself. The guys at metasploit seemed to have it very clear since the beginning as well.

Here’s the same algorithm shown in Python, this time in Ruby. It follows a different approach, which shows also the tendency of Ruby to use a slightly more functional style.

hamming = Enumerator.new do |yielder|
  next_ham = 1
  queues = { 2 => [], 3 => [], 5 => [] }

  loop do
    yielder << next_ham   # or: yielder.yield(next_ham)

    [2,3,5].each {|m| queues[m]<< (next_ham * m)}
    next_ham = [2,3,5].collect {|m| queues[m][0]}.min
    [2,3,5].each {|m| queues[m].shift if queues[m][0]== next_ham}
  end
end

idx = 1
hamming.each do |ham|
  case idx
  when (1..20), 1691
    p [idx, ham]
  when 1_000_000
    p [idx, ham]
    break
  end
  idx += 1
end

Scala

Seems to be winning the race for the best JVM-based language award. I’m pretty sure that most of it comes from a familiar syntax, when compared with Clojure, the other big contender. As in Clojure, the reason this language is in this list is because its easy interfacing with Java make it a viable choice for a real project. Look at this small snippet generating the Hofstadter Q sequence:

object HofstadterQseq extends App {
  val Q: Int => Int = n => {
    if (n <= 2) 1
    else Q(n-Q(n-1))+Q(n-Q(n-2))
  }
  (1 to 10).map(i=>(i,Q(i))).foreach(t=>println("Q("+t._1+") = "+t._2))
  println("Q("+1000+") = "+Q(1000))
}

Scheme

This is probably a controversial language to be on this list, but I have an explanation. The three main issues associated with this language are:

  1. Lack of one true implementation and multiple competing ones of dubious quality.
  2. Lack of libraries.
  3. Poor performance.

Well, the first one is partially true (there are too many implementations), but there are only a handful of good ones and you need to choose the one that best fits you. The second is also partially true: there are libraries, but they are scattered. There are some projects that offer alternatives, and lots of tiny projects out there. The fragmentation of the language is made obvious when looking for support code: you need to make it work with your implementation. However, this is often not so difficult or time-consuming, and most importantly, if you use Scheme implementations with good FFI support, such as Gambit or Chicken Scheme, you have easy access to all those libraries in C. I actually do it, and works great, contrary to what you may think. Finally, poor performance. This one is actually completely false. Implementations such as Gambit are very fast, and you have plenty of options for optimization (starting from algorithmic optimization, global Scheme compiler declarations, and of course, C code that can be easily interwoven with the Scheme code when necessary).

Yes, I’m fanatical about Scheme, however, I admit it has one deadly weakness: it’s an awful language for sharing code, with a not-so-good community. It’s so flexible, that every single programmer wants its own little perfect solution to the task. It’s the complete opposite to Java: great for individual/small-team projects, prototyping and exploratory programming, unproven for large teams. But in those situations, is perfectly fine, and you can actually ride an extremely fast and pleasant development cycle. Lastly, another very interesting feature of the language: you can easily compile to Javascript with one of the Scheme-to-Js compilers, so you could enjoy the same kind of symmetry that you get when developing with Node.js on the server. The following are concrete examples where I’d use this language:

  • For exploratory programming, when I don’t exactly know where I’m heading.
  • For fast prototyping of ideas that don’t really require a large library only available in languages like Python or Ruby.
  • For scripting large programs or platforms developed in C/C++.
  • For building an application with large portions that need to be written from scratch.
  • For games and OpenGL/ES-based multiplatform applications.

Here you have three examples of Scheme code. You actually have to implement these functions yourself as they are not directly available across all implementations, even though they are rather useful and common enough. These would work across all implementations (provided they are R5RS-compatible).

;;! Recursive map that applies function to each node
(define (map** f l)
  (cond
   ((null? l) '())
   ((not (pair? l)) (f l))
   (else
    (cons (f (map** f (car l))) (f (map** f (cdr l)))))))

;;! Explicit currying of an arbitrary function
(define (curry fun arg1 . args)
  (if (pair? args)
      (let ((all-args (cons arg1 args)))
        (lambda x
          (apply fun (append all-args x))))
      (lambda x
        (apply fun (cons arg1 x)))))

;;! Implementation of filter, with the match macro
(define (filter p lst)
  (match lst
   ('() '())
   (((? p) . tl) (cons (car lst) (filter/match p tl)))
   ((hd . tl) (filter/match p tl))))

Take a look at these other interesting examples too.

If you solve the issue of a minimal development framework (yourself or via projects like Scheme Spheres, then you are on a flywheel.

Dinosaur languages

Not necessarily good or bad. They just seem to be forgotten, there is no more hype about this languages, and there seem to be no compelling reasons to use them. But maybe we are wrong!

Assembly

Nobody really codes in Assembly any more, not even for optimization, since compilers are much better at this task. Well, there is always someone better than the compiler, but you must be very, very smart and knowledgeable for that I presume.

But there is one very important reason why you must use it: for the ultimate programming experience. There is this enlightening experience that you are blessed with SICP and the Lisps, but I believe there is this other enlightenment that comes with really understanding what all languages end up being: just a sequence of processor instructions, that abstract away from languages their own high-level constructs, no matter if they are declarative, logic, functional or object-oriented. That’s power for your programmer brain. This is a language that belongs in The Great Languages category. When would I use learning?

  • For learning.
  • For systems development there are some situations where you need to use it.
  • When you know a lot about an specific architecture and need a specific portion of code to be hand-crafted.

Common Lisp

I’ve used Autolisp, for AutoCAD automatization, but once faced with the Lisp/Scheme/Clojure decision, I choose Scheme. For me, it ranks third among the three reasonable Lisps. It feels bloated and missing the most important features of a lisp: beauty, elegance and simplicity. I would use it for rapid prototyping, it has the advantage over Scheme of the readily available libraries, but we’ll see that Scheme makes up for this disadvantage. And, I think there are better languages for prototyping with libraries.

Perl

Great songs have been written in Perl. Apparently is a language of religion, with its monks and its prophet. There is something to the fact that Larry Wall, its creator, is a linguist, something that you can see projected into the language. Feels like the Latin of programming languages, which I find really fascinating. Guys, wise folks in the industry are still talking about Perl, so there must be a reason. The spirit of the language is captured in one of Larry’s witty quotes ‘Real programmers can write assembly code in any language’.

Overall, I can say I am impressed by the linguistic notions in Perl. But its funny syntax could be used for great harm in the wrong hands (much in the way Lisp macros can). I’d say the language is great for solving small tasks in a very handy way: it has a comprehensive set of libraries (CPAN) for almost any task you want to, leading to the simplest solutions that could possibly work. Using Perl the worst that could happen is that you learn a very valuable tool for scripting your system. Ps: I’ve been told Perl’s object support it’s plain terrible, but I count this as a benefit (I might be biased, though), but I also doubt this assertion.

Check out this two great projects: POE (a framework for reactive systems, cooperative multitasking, and network applications), and Mojolicious, a real-time web framework.

BASIC, COBOL, Fortran, Pascal, Visual Basic…

The gods have mercy with you if you need to program in any of these languages. They may have a very specific usage (like, Fortran in the Astronomy and HPC communities), or COBOL (large legacy systems in industries such as banking), but they all get almost unanimously bashed by the developers community. But I offer you a very good reason to use these languages: you’ll be able to sport a pretty sweet hourly rate for fixing code of others. For your own code? Don’t even thing about it ;)

Smalltalk

The first true object-oriented language. But it seems to me Smalltalk is pretty much a forgotten language.

The Unreasonable languages

Unreasonable probably for production purposes, but will definitely make you a better programmer (that being perfectly reasonable). Your is the choice of what counts. And what I can say, I love unreasonable options.

Array, J

These are languages that I need to learn, as I’ve heard that they are unique and learning them will expand your mind beyond functional and declarative languages.

Factor, Forth

Stack-based languages are also very powerful and worth learning. Useful for expanding the mind. On my TODO list.

F#

Microsoft trying to be cool. It’s a nice language, but many of us have learned to keep away from Microsoft the hard way. We have enough company-sponsored languages already.

Oz

It’s a very multiparadigm language, with constraint and distributed programming functionality. It has most of the features of the major programming language including functional (both lazy and eager), imperative and object-oriented.

Prolog/Datalog

Declarative logic languages are generally very academic languages. There are exceptions though, as can be seen in this Stackoverflow question, and the same could be said about Scheme.

Rust

Mozilla’s contender to the systems programming language competition. It doesn’t have the history of D behind it, or the support of a huge company as Google, such as Go does. Still, I hope to see Rust as a reasonable choice for systems development in the near future.

Shen

This is just here because I read interesting stuff about skinnable type systems, and some other very radical and interesting ideas in Shen. However, its implementations are extremely experimental and the language has an unacceptable license. The creator seems to live in another decade.

TCL

I used it for a few months, when the fact that it is homoiconic and it had bindings to a library I needed back then (BRL-CAD) was all that mattered. I’d say is an underrated language, but just as so many others are. It doesn’t shine with any super-cool features either (à la Erlang).

Conclusion

I started this long post with my selection of choice. Programming is a beautiful craft, that I love whole-heartedly, so I admit that I’m heavily biased according to my personal experience. Choosing a programming language for a task or project is sometimes difficult, as so many variables take place. In my opinion, there are three that prevail, in this order:

  1. Is the project aimed at production, or belongs to a sufficiently large organization with a culture or bias towards a programming language?
  2. Is the task at hand sufficiently special to require a programming language with very specific features?
  3. Do you love or want to try developing in that programming language?

That’s how I approach this issue. Even though sometimes I break the rules…

Do you have any code snippets that better represent these languages?


Did you find it useful? Please share!

Comments