Wednesday, September 23, 2009

Ruminations on programming languages

For a long while I was reasonably content with my main programming languages--mostly C++ and a bit of Python. They're both great languages (although C++ is also a terrible language, of course.) I've used a lot of different ones, and they all have their strengths and flaws. But none of them are perfect.

So as a side project, I attempted many times to design my idea of the ultimate programming language. It would combine the power of Lisp, the readability and whippitupitude of Python, and the performance of C with advanced static type safety and formally provable correctness. And a pony.

Somewhere along the way, though, I was temporarily struck by a bit of humility. I thought I should learn more about the state of the art in other programming languages, rather than risk reinventing the square wheel. So I learned about Oz and Erlang and Haskell and SML. And I discovered that, basically, the state of the art in programming languages is pretty damned good. So good, in fact, that my attempts to advance it started to look pretty lame.

But now I had a new problem: having spent some time using Erlang and Haskell for side projects, I couldn't stand programming in C++ any more. There were just too many things that were painful and verbose that would have been trivial in Haskell. But Haskell, beautiful though it is, still makes some things difficult that are easy in a stateful language. I wasn't totally happy there either. Python was still nice, but for larger projects I much prefer static typing. Basically no matter what language I was using, I was frustrated by things that should have been trivial, and would have been trivial in some other language.

This sorry state persisted for a few years, and it made programming at work not all that enjoyable any more. But lately I've been primarily using C#, and I've found to my surprise that it's actually making programming fun again. Yes, C# started life as a Java clone, but then it got a really good generics design in 2.0 and iterators, and a little bit of type inference and nice Lambda-function syntax in 3.0. Throw in the Enumerable extensions in the libraries, and you start to have pretty nice support for functional programming. And while it's not Haskell, generators and enumerators give you a little taste of that crazy control-flow power without going so far as to actually turn your brain inside out. It's quite nice.

In another post I'll explore some functional-style code in C#.