Time to learn a new language

I have something of an informal goal of learning a new programming language every few years. It’s not so much a goal as it is something of a discomfort. There are so many programming languages out there, with so many niches and approaches to problems, that I get uncomfortable with my lack of knowledge of some of them after awhile. This tends to happen every few years.

The last major language I learned was Haskell, which I started working with in 2004. I still enjoy Haskell and don’t see anything displacing it as my primary day-to-day workhorse.

Yet there are some languages that I’d like to learn. I have an interest in cross-platform languages; one of my few annoyances with Haskell is that it can’t (at least with production quality) be compiled into something like Java bytecode or something else that isn’t architecture-dependent. I have long had a soft spot for functional languages. I haven’t had such a soft spot for static type checking, but Haskell’s type inference changed that for me. Also I have an interest in writing Android apps, which means some sort of Java tie-in would be needed.

Here are my current candidates:

  • JavaScript. I have never learned the language but dislike it intensely based on everything I have learned about it (especially the diverging standards of implementation). Nevertheless, there are certain obvious reasons to try it — the fact that most computers and mobile phones can run it out of the box is an important one.
  • Scheme. Of somewhat less interest since I learned Common Lisp quite awhile back. I’m probably pretty rusty at it, but I’m not sure Scheme would offer me anything novel that I can’t find in Haskell — except for the ability to compile to JVM bytecode.
  • Lua — it sounds interesting, but I’m not sure if it’s general-purpose enough to merit long-term interest.
  • Scala sounds interesting — a OOP and FP language that compiles to JVM bytecode.
  • Smalltalk. Seems sad I’ve never learned this one.
  • There are some amazing webapps written using Cappuccino. The Github issue interface is where I hear about this one.
  • Eclipse. I guess it’s mostly not a programming language but an IDE, but then there’s some libraries (RCP?) or something with it — so to be honest, I don’t know what it is. Some people seem very excited about it. I tried it once, couldn’t figure out how to just open a file and start editing already. Made me feel like I was working for Initech and wouldn’t get to actually compile something until my TPS coversheets were in order. Dunno, maybe it’s not that bad, but I never really understood the appeal of something other than emacs/vi+make.
  • A Haskell web infrastructure such as HSP or hApps. Not a new language, but might as well be…

Of some particular interest to me is that Haskell has interpreters for Scheme, Lua, and JavaScript as well as code generators for some of these languages (though not generic Haskell-to-foo compilers).

Languages not in the running because I already know them include: OCaml, POSIX shell, Python, Perl, Java, C, C++, Pascal, BASIC, Common Lisp, Prolog, SQL. Languages I have no interest in learning right now include Ruby (not different enough from what I already know plus bad experiences with it), any assembly, anything steeped in the Microsoft monoculture (C#, VB, etc.), or anything that is hard to work with outside of an Emacs or vim environment. (If your language requires or strongly encourages me to use your IDE or proprietary compiler, I’m not interested — that means you, flash.)

Brief Reivews of Languages I Have Used

To give you a bit of an idea of where I’m coming from:

  • C: Not much to say there. I think its pros and cons are well-known. I consider it to be too unwieldy for general-purpose use these days, though find myself writing code in it every few years for some reason or other.
  • Perl: The first major interpreted language I learned. Stopped using it entirely after learning Python (didn’t see any advantage of Perl over Python, and plenty of disadvantages.)
  • Python: Used to really like it. Both the language and I have changed. It is no longer the “clean” language it was in the 1.5 days. Too many lists-that-aren’t-lists, __underscorethings__, etc. Still cleaner than Perl. It didn’t scale up to large projects well, and the interpreted dynamic nature left me not all that happy to use it for some tasks. Haven’t looked at Python 3, but also it probably isn’t ready for prime time yet anyhow.
  • Java: Better than C++ for me. Cross-platform bytecode features. That’s about all that I have to say about it that’s kind. The world’s biggest source of carpal tunnel referrals in my book. Mysteriously manages to have web apps that require 2GB of RAM just to load. Dunno where that came from; Apache with PHP and mod_python takes less than 100M.
  • Haskell: A pretty stellar mix of a lot of nice features, type inference being one of the very nice ones in my book. My language of choice for almost all tasks. Laziness can be hard for even experienced Haskellers to understand at times, and the libraries are sometimes in a bit of flux (which should calm down soon). Still a very interesting language and, in fact, a decent candidate for my time as there is some about it I’ve never picked up, including some modules and web toolkits.
  • OCaml: Tried it, eventually discarded it. An I/O library that makes you go through all sorts of contortions to be able to open a file read/write isn’t cool in my book.

53 thoughts on “Time to learn a new language

  1. Objective-C. Very clean, elegant mix of C and Smalltalk. I think it’ll take you about an hour to learn. Benefits: you get to check out Mac OS & iPhone programming with Cocoa.

    1. I’d second Vala as a good choice, particularly if you have any interest in GTK or GUIs. It provides a decently high-level language while still compiling to native C, which puts it on an even footing with Haskell and few other modern languages in terms of providing native binaries.

  2. You mention interest in something that isn’t architecture-dependent. The current premier implementation of Perl 6 (“Rakudo”) runs on the Parrot VM. No idea about the possibility of running Parrot on Android, though. It’s pretty easy to try out Rakudo (the build commands even grab and build Parrot for you).

  3. Out of the options you listed I would say Scheme. In my opinion, the most interesting thing about Smalltalk is the environment which would be very much against your “hard to work with outside of Emacs/vim” and also a bit of a “monoculture.”

    One other option you might consider is J, except it doesn’t work on the JVM. It’s the language most unlike any of the ones you know. It’s a rather fun language, but, unfortunately, I don’t see it becoming one of your main languages.

  4. What about Ada ? It’s not been mentioned yet. Sufficiently different from your repertoire to be of interest. It’s my personal second favourite (Haskell is first) and is more oriented to your preference for software engineering over hacking.

  5. Given your preference for something on the JVM, I’d say go for either Scheme or Scala. Scheme is quite small, but somewhat surprisingly (for me at least) the core of Scala is also smaller than Java.

    Not sure about Scheme on the JVM, though, so in practical terms Scala is probably the best since it let’s you tap into the whole JVM ecosystem without having to jump through hoops.

  6. I would suggest trying out Erlang. It’s perfect for server based software. You could for example take a look at Ejabberd, Webmachine, Nitrogen project or Zotonic for inspiration.

  7. >> I’m probably pretty rusty at it, but I’m not sure Scheme would offer me anything novel that I can’t find in Haskell

    Real macros, hygienic or not ? Macrology is far from trivial, and I can’t think of anything in Haskell that would be close to it.

    >> An I/O library that makes you go through all sorts of contortions to be able to open a file read/write isn’t cool in my book.

    What about debugging some “purely functional code” ? I don’t find haskell’s solutions to be cool : it takes more code than just a print statement.

    As far as I can find fun in it, I’d go for Scheme or Smalltalk (but that’s an implementer bias, I guess)

    1. To be quite honest with you, Haskell’s purity is one of the most appealing things of the language. To those of you that don’t know what I’m talking about, anything that can have a side-effect (modifying some sort of variable, altering the state of the world by performing I/O, etc.) is segmented out into its own box, and good form says that you try to put as little in that box as possible.

      As a result, you can’t, of course, call printf from pure code. But you *can* just run functions with arbitrary inputs from ghci, since you know they will always produce the same result from the same input. Moreover, you can use QuickCheck or friends to automatically generate comprehensive test cases for them.

      I will very much miss this in other languages, I believe.

      1. Well, the semantics within GHCI and the semantics of compiled code are quite different. I’m pretty sure that real-life code is compiled, not interactively run from GHCI.

        Also, a compiled program must have the main entry point. Now, the interesting thing is the type of main :: IO ()
        Which means that the whole program is in an IO monad, and this makes the purity case bogus to me! The purity argument is nice on paper, but I am really not convinced as far as reality is concerned (or at least GHC, the only implementation I use). Therefore, I see no difference between (compiled) Haskell and Caml as far as factual and actual purity is concerned,

        1. The semantics within GHCi and in compiled code are of course the same… (though optimisations may change the strictness behaviour of your compiled code but only in a good way and that’s not a part of semantics)

          You don’t seem to have spent much time investigating Haskell, while main type is IO () (of course, if you don’t interact with the outside in a lazy language nothing would ever be evaluated), Haskell philosophy is to use a thin layer of IO code around a pure core (you can look at XMonad to see how this is an interesting and appliable concept).

          Also trace a b is a function that allows a prinft-like debug method. As for your example if that’s something you find yourself needing frequently, you can simply define :
          traceIf True = trace
          traceIf False = const

      1. Indeed, it seems quite convenient.
        Yet, I think it requires more code refactoring because of lazyness..
        fact 1 = 1
        fact n =
        if (mod n 2 == 0) then trace (show n) r else r where
        r = fact (n – 1)
        versus
        let rec fact x = match x with
        | 1 -> 1
        | n ->
        if (n mod 2) = 0 then print_int n;
        fact (n – 1);;
        fact 10;;

        So it’s not as convenient to me.
        Yet, now you showed it to me, I am very looking forward to using it, so that I can evaluate my own bias with more accuracy.

  8. Javascript. Start with watching the JS videos of crockford. He may be an old bullhead (see his “may be used for good not evil” license), but his lectures are fun to watch and he has something to say on JavaScript.
    JavaScript is used inside CouchDB to write the map/reduce functions and the view logic. CouchDB itself is written in Erlang.

  9. I’d 2nd Clojure. It’s a Scheme made more Haskell like but exists purely for the Java ecosystem so has very easy integration with Java.

  10. I would also second Clojure. I had been using it for a while and am liking it very well. I haven’t used a lot of Java interop but what I have used so far is very nice.

  11. I am an OCaml enthusiast

    >> An I/O library that makes you go through all sorts of contortions to be able to open a file read/write isn’t cool in my book.

    I am not sure to see what you mean by this. Maybe you can give more details.

    You should maybe look at OCaml a second time. There are a lot of new things all around:
    * JVM support through ocamljava (http://ocamljava.x9c.fr/)
    * Ability to run native OCaml application on Android (http://sites.google.com/site/keigoattic/ocaml-on-android)
    * Direct compilation to JavaScript (http://code.google.com/p/ocamljs/) or use a VM to interpret OCaml bytecode (http://ocsigen.org/obrowser/)

    Of course, you won’t have to leave Vim/Emacs to work on it. It also shares features with Haskell you should enjoy (e.g. type inference, though you don’t have GADT).

    1. Look at http://caml.inria.fr/pub/docs/manual-ocaml/libref/Pervasives.html#TYPEin_channel . OCaml has an in_channel and an out_channel type as its basic I/O support. The type of a handle opened for reading is different than that of one open for writing. You’ll even note there’s an open_out and open_in for opening files for output or input. Nothing in Pervasives for opening files for reading and writing (a very common thing possible in every other language I’ve ever used on every modern platform.) The fact that this problem still exists 6 years after I stopped using OCaml says a lot to me about how little innovation there is in that field, despite your examples.

      The workaround I had to use was the Unix module. With it, you can open a file read/write. But of course, it isn’t portable. And all the other libraries out there that deal with I/O expect the in_channel or out_channel.

      This strange setup results in craziness like seek_in, seek_out, close_in, close_out, etc. Different functions that map to the same underlying calls.

      And this isn’t the only area where this happens. OCaml has both lists and streams. They solve essentially the same problems, but lists are strict and streams are lazy. Some library functions want one, others the other. As far as I know, the only argument for the separate types was performance.

      The build system, last I looked, was nonexistent. Writing a library was a complex task. There were so many “standard” build systems that all of them were rather complex and unwieldy. It was made more so by some people wanting to compile to native code via ocamlopt, others wanting bytecode, and some platforms not supporting ocamlopt. There were various complex Makefiles and some that even used autoconf. Already back then, Haskell had Cabal which, despite its flaws, made things much easier.

      I will say that the Java, Android, and JavaScript stuff sounds interesting. But the underlying language feels like something that in some ways needs to be pulled out of the 1970s. I mean, really, the I/O system not being able to open a file read/write? Crazy.

      1. Unix module is in fact portable. Look here
        http://caml.inria.fr/pub/docs/manual-ocaml/manual035.html

        There are some exception like “fork” which are not implemented, but they are all listed on this webpage.

        So basically you can use Unix module R/W file in a portable fashion. The open_in/open_out is to prevent error like writing to a read-only file handle… This is not a common feature (or bug) but a design choice. Honestly, since the Unix module is portable I don’t see this a real problem.

        All the examples you give are portable in the Unix module: seek, open, read, write, close.

        There is now a standard build system provided with the core distribution: ocamlbuild. It is still under development and evolving quickly:
        http://brion.inria.fr/gallium/index.php/Ocamlbuild

        Last but not least, a Cabal like tool is under development:
        http://oasis.forge.ocamlcore.org/

        Regards

        1. OK, I’ll accept that Unix is portable, but there is still a problem: now there are *three* different types that correspond to a file descriptor: in_channel, out_channel, and file_descr. All of these are incompatible with each other (though a file_descr can be converted to an in_channel or out_channel).

          So if my program uses a file that’s opened read/write, and perhaps a few modules that interface with that file, what types will be used? Probably all three. Some modules might use file_descr for flexibility. Others might want the out_chan for writing or the in_chan for reading. Now I have to manage the conversions myself. A large pain. (Incidentally, if one really wanted the language types to enforce this notion, Haskell typeclasses could have made it all quite transparent and easy, I believe; does OCaml really lack the ability to do that, forcing this close_in, close_out silliness on us?)

          It may be a design decision, but it is not one without consequences if the standard language libraries can’t handle read/write files.

          Here’s another example: + only works on ints. There is a separate +. that only works on floats. 5.5 + 6.3 won’t work on OCaml; you’ve got to say 5.5 +. 6.3. There is no + for an Int32 or Int64 (have to use the “add” function instead.) Haskell’s typeclasses permit complete type safety in this regard, without resorting the +. nonsense (and with still letting me define my own numeric types that can be used with +). This lack of extensibility in the core language makes it frustrating and uninteresting. See http://changelog.complete.org/archives/339-why-i-love-haskell-in-one-simple-example for an example of what I mean.

          And this perhaps gets to the core of why OCaml drove me nuts: there would often be some standard way of doing something, which would be widely accepted but also widely inadequate for some common tasks. So there would be various alternative, incompatible options to solve the problem. Some modules would use the inadequate standard, some the bolt-on alternative, and you wind up with a mess of incompatible libraries and having to choose data types based on library support. The various I/O types, lists vs. streams, weird numeric operators, etc. I can’t even write a function that can add both ints and floats! That’s partly what drove me to write MissingLib back then.

          It is good to hear that the build system is improved, but sad to see that the core libraries haven’t.

  12. Given that you seem willing to consider major advances in languages you already know, I have two suggestions:

    – Template Haskell, if you don’t already know it. (I’d also suggest uniplate as a nice library for dealing with its objects.)

    – talloc. C with decent memory management feels like an entirely different language. ;)

  13. Lua is always a good thing to know about. It is fast, doesn’t eat tons of memory and it is not too hard to learn. Also there are a lot of nice applications which use Lua – awesome or Lighttpd’s mod_magnet for example.

    1. I admit to having never used LLVM before, but my understanding is that this isn’t what I meant by platform-independent. LLVM code must still be compiled to native machine code. The benefit of the Haskell LLVM backend lies in simplification of code generation and possible performance, not in portability. LLVM targets Unix-like platforms according to their FAQ and perhaps isn’t useful on Windows.

  14. Yeah, I considered Haskell or Scala as a first FP language but settled on Clojure in the end, partly because all of the cool kids are learning it, but also I found the talks by Rich Hickey posted on the clojure.org site compelling. I’m pleased so far with it. Very natural to me, coming from Ruby, and even if I don’t use this for any real projects, it gives me a whole new perspective I hope I can apply to my coding practices.

  15. If you give Perl (5!) another whirl and make sure you learn today’s tools, you’ll find it a different language than just a few years ago. Have a look at Moose for OOP and the Task::Kensho bundle on CPAN for a list of high-quality modules for various tasks. Google for “modern perl” for the talk. If you’re into web-development, read Kieren Diment’s and Matt S Trout’s “Definitve Guide to Catalyst”. I doubt you’ll regret it.

  16. ObjC makes sense, yes. A friend is writing a (non-Apple/GNU specific) framework and even runtime for it right now.

    Also, mksh (and Korn Shell in general) might make sense, you’d be surprised just how much works there if you go beyond shell scripting to shell programming.

    Limbo (the language of Inferno from Vita Nuova – basically Plan 9 in a VM) is cool. And it’s strongly related to Google-Go.

  17. My vote is for Lua. It’s a fun small language. There’s really not a whole lot (if really anything) holding it back from being a generally used language in your day-to-day coding. If there’s ever something it can’t do on its own, most likely C can do it, and have Lua bindings (easy with SWIG, and fairly straight forward if you write the bindings by hand with the Lua C-API.)

    I code in JavaScript to make web applications in my day job. It’s actually a pretty interesting language because it’s a functional language disguised with C/C++ syntax. That said it does some pretty dumb things that makes the language tricky to code in. Things like jslint make for checking the code for common mistakes a bit easier to spot. I highly recommend reading this (even if you don’t choose JavaScript) http://javascript.crockford.com/javascript.html

    Clojure might be of interest to you in general because I believe it’s basically Common-Lisp that compiles to and uses the JVM.

  18. My picks:

    Smalltalk – I don’t think a software engineer is complete without spending some time look at some Smalltalk systems. Squeak is the exemplar of platform-independence. Squeak and Smalltalk generally is in renaissance right now.

    Newspeak – a more functional smalltalk/self-like system. Good stuff.

    Clojure – Modern insightful functional programming, lisp and the java ecosystem.

    Scheme – PLT Scheme in particular. Principled, innovative, active and practical.

  19. Unix module is in fact portable. Look here
    http://caml.inria.fr/pub/docs/manual-ocaml/manual035.html

    There are some exception like “fork” which are not implemented, but they are all listed on this webpage.

    So basically you can use Unix module R/W file in a portable fashion. The open_in/open_out is to prevent error like writing to a read-only file handle… This is not a common feature (or bug) but a design choice. Honestly, since the Unix module is portable I don’t see this a real problem.

    All the examples you give are portable in the Unix module: seek, open, read, write, close.

    There is now a standard build system provided with the core distribution: ocamlbuild. It is still under development and evolving quickly:
    http://brion.inria.fr/gallium/index.php/Ocamlbuild

    Last but not least, a Cabal like tool is under development:
    http://oasis.forge.ocamlcore.org/

    Regards

  20. I learned Ruby on Rails this year. I liked it a lot more than I thought I would. It is unparalleled for getting work done, for certain definitions of work.

    Did your python experience include generators? I missed that constantly when I left but I’m finding Ruby 1.9 to be pretty close.

  21. I’d highly recommend Erlang, it’s syntax is not the best, and you will probably miss currying, but the way functional concepts are used to advance concurrency is absolutely unmatched. Even if you don’t end up using it for anything, the Erlang way of doing things is enlightening.

    My second vote would be for Go, depending on why you want to learn a new language. Go isn’t something you’d use for anything probably, but it’s a small language you could pick up quickly, and it has some neat concepts (admittedly borrowed from other languages). If you want to scratch that “learn a new language” itch, but don’t want to spend a ton of time learning a super deep language, Go is pretty fun.

  22. If you do go the JavaScript route, I’d highly recommend the book “JavaScript: The Good Parts”. After years of avoiding JS as much as possible, I finally decided it was time to learn it properly. After going through the various JS articles at http://javascript.crockford.com/ I decided to buy the book.

    It turned out that much of what I disliked about JS was actually the DOM bits. JavaScript is quite pretty and fun! That surprised me to no end!

    And, another vote for ruby even though it’s not on your list. I’ve never had more fun programming than I have with Ruby. :) Of course, that’s after years and years of perl5, java, shell scripting, etc.

  23. The Omega programming language seems worthwhile, if you want another functional programming language. Omega offers dependent typing.

  24. Is the Java process really that big. We have a 3rd party Java component that looks to be about 800MB in size, but if you dig into it most of it ismemory mapped data. Although one does wonder why a program that does a simple cryptographic function needs to map 800MB of data, I assume it is including library behaviour it will never use.

  25. Lua is useful if you want a dynamic language that has a tiny runtime implementation and a simple C API. Otherwise, I wouldn’t bother.

    Regarding Python, I’ve used nearly every major release from 1.5.2 to 2.6, and I’m still quite content with it. I guess I haven’t encountered any Python-specific difficulty with large projects. And it doesn’t feel any less clean now than it did when I started.

    Now you’ve got me thinking that I should learn Haskell. I admit I’m somewhat prejudiced against it, because I’m content with dynamic typing, and I’ve read some of Steve Yegge’s rants against static typing and the Hindley-Milner type system in particular. But I know one size doesn’t fit all, so I’ll give Haskell a try sometime.

  26. I’m also interested in doing Android development and personally have no interest in Java. I recently heard about Duby, a Ruby-like language that has no runtime need besides the JVM (unlike other JVM languages). Looks interesting.

Leave a Reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.