Learning a new language to improve your programming skills is a cliché. I realized recently (and I'm into languages) that tinkering on a project in a different domain is hundred times more educational and fun.
E.g. if you mostly do webapp backends, write a ray tracer in Javascript. If you're a systems programmer, write a blog on AppEngine. Make a screensaver. Make an iPhone app. Etc etc.
I think the advice to learn a new language is more incomplete than anything else; it's not learning a new language that's valuable, it's learning new ways to think about problems. Picking up a language that's very similar to one you already use, or that differs only in matters of syntax, isn't really going to do much for you, and it probably wouldn't take more than maybe six carefully-selected languages to get 99% of the benefit learning new languages will ever have.
Writing a program in a radically different domain than what you're used to has a lot of the same value, plus the advantage of being a much less exhaustible resource.
I think the advice to learn a new language is more incomplete than anything else; it's not learning a new language that's valuable, it's learning new ways to think about problems.
Learning a new language, on its own, isn't very beneficial - learning a new language thats different to the ones you already know is very beneficial. If you primarily work with statically typed languages, try a dynamically typed one (or one with type inference). If you're used to object oriented languages, try a functional language. If you're used to monitor based concurrency, try actor based concurrency. If you're used to imperative programming, try dataflow. If to you macro means the C preprocessor, try a language with lisp-style macros.
Its about the paradigms, core features, abstract concepts - not the languages themselves. If you know C++ and Java, you probably won't get much out of learning C#, aside from different APIs and libraries, but if you instead learn F#, you would get a lot out of the experience of using a completely different paradigm for conceptualizing and reasoning about problems. Thats why I like tinkering with languages that are radically different from the ones I already know.
Of course, this means that when you learn a new language, you have to put a conscious effort into programming in that languages idiomatic fashion. Programming in Haskell as you would program in Java isn't going to teach you anything and will probably only make you frustrated at how hard the language appears to make your life.
"and it probably wouldn't take more than maybe six carefully-selected languages to get 99% of the benefit learning new languages will ever have."
I don't know how you came up with these numbers- from what I've seen of the variety language of programming languages out there this doesn't seem at all supportable. Not unless you take a completely reductive sampling of the various computer languages that have been developed thus far.
But yes, tackling different kinds of problems and different kinds of program languages will certainly give you healthy and open-minded perspective about programming.
* C++, Java, C# or some other imperative OO language
* Scheme, Common Lisp, Clojure or some other lisp
* Haskell, OCaml, Scala or F# (and maybe Erlang?)
* Prolog or Mercury
* LabVIEW, Luster/SCADE or some other dataflow language
* Factor, Forth, Joy or Cat
This gets me imperative/OO, monitor based concurrency, Lisp-ness (homoiconic language, real macros, DSLs), functional, strong static typing, type inference, powerful type systems, logic programming, dataflow and concatenative.
Yes, there are gaps - I'd also add Oz, Python/Ruby/Boo/Groovy and J into the mix to get a more fully rounded paradigm tour and, even then, there are some things missing, though at this point you should have a strong knowledge of languages and paradigms and should be able to tackle most problems pretty well - or at least, know enough to choose a good programming language for the task at hand.
Hmm, after looking at your rather nice list, six was probably too low; I think I'll revise my estimate to a more conservative eight. There'll always be some gap, of course, but eight ought to get closer to the point of diminishing returns I had in mind.
Incidentally, I'd probably include some form of assembly as well, for the whole "must understand the underlying hardware" aspect.
Ohhh! That was certainly an oversight on my part - an assembly language should be included.
Eight should be enough, after that, you probably wouldn't learn enough to make the effort worthwhile (except maybe to learn a language for a particular need, eg available libraries). I think my number seven then would be an assembly language and my eight would be Oz, ATS[1] and J[2] (not really in the same category, but more of a misc interesting languages category). I would then add Python/Ruby/Boo/Groovy in with C++, C# and Java.
ATS and J are both unique in their own ways. I'm not sure what value there is in learning either of these (since I don't know them) but they seem different enough to teach you something new. J (or APL or K) do teach you about array processing languages and point-free programming, so maybe this is useful. ATS is interesting because of its emphasis on types in a way I haven't seen in other languages:
I'd actually be inclined to get C++/C#/Java off the list entirely due to not showcasing any one perspective particularly well, to be honest. Smalltalk or Ruby would better illustrate OOP, and between them the OOP language and the assembly should cover the basic procedural approach well enough, I think. Also, plain old C could possibly stand in for the assembly, especially if you were mostly using it "portable assembly" style instead of relying mostly on libraries.
For what it's worth the list I had mind originally was something like:
* C, for low-level procedural and machine-awareness
* Ruby, for high-level procedural and OOP (plus scripty perl-isms)
* Scheme, for distilled lisp-iness without distracting details
* Haskell, for HM static typing and functional purity
* Two empty slots to cover languages I'm less familiar with
After seeing your list, I realized I'd carelessly underestimated the number of empty slots necessary...
That old saw is really about points of view, as you note. Going from C to Pascal isn't really going to teach you very much. Going from C to programming idiomatic Prolog is a huge shift, and teaches you a new way to look at things.
I beg to differ. Learning a new language[1] also means learning to know a different paradigm & culture & ecosystem. You learn to know novel ways of doing things that you can transfer to your main programming language---or not.
Tinkering on a project in a different domain most likely means learning to know new libraries and maybe new tools. But those are most often just more of the same and don't help you to get a new perspective on what you're doing.
Instead of just learning a new language, I'd also suggest to read related CS papers.
[1] With "new language" I mean a language that puts emphasis on a paradigm you are not familiar with yet. E.g. if you're a ruby programmer, I wouldn't consider python a "new language"---and vice verse.
Learning a new language to improve your programming skills is truly a cliché. Instead the proper advice should be "I should learn a new programming language so I can escape my myopic understanding of the practice programming." Building applications, as you say, is of course very instructive, but tackling a language which has very little relation to the ones with which you are familiar has benefits which are pointless to reduce to "it will make you a better programmer".
It may be a less useful technique to improve programming skills when you are well versed in different kinds of languages but it could be argued that what you are striving for with your projects in different fields can be achieved when someone who has programmed for 5 years in java and only java goes and learns how to do substantial things in a language like haskell.
Bypass the whole lot and "learn" Mozart/Oz. The most elegant kitchen-sink of programming paradigms. It's so good nothing useful has ever been written in it. It's the subject of the second greatest text on computer programming.
Mozart/Oz, it's like programming the way the classic Vienna Musician would have written Music, if he moved to Bondi Sydney and picked up surfing and wild-growing marijuana.
Mozart/Oz is, indeed, a very interesting and powerful language and certainly one of the more complete multiparadigm languages. After reading Peter Van Roys CTM, I told myself that I would learn and use Oz, but... it never happened.
"Factor is to Forth what Clojure is to Common Lisp"
I disagree. Its well known in the Factor community that, as one of the core Factor devs stated, idiomatic Factor doesn't use the stack; its only superficially related to Forth in that it uses similar syntax, but it has much more in common with lisp.
Sure, Factor is stack based - like Forth - but Factor provides a lot of abstractions on top of this (many of which are inspired by lisp), which Forth does not, like macros, combinators (which help avoid manually dealing with the stack), local variables, lisp-style lists, concurrency, generics, object oriented programming, even infix expressions (though the use of a macro)... and a ton more.
I find the list slightly disappointing. Those languages are listed in almost every other list of that kind. Checking out new entries in the language shootout is more informative.
Has Io been useful in any application yet? Admittedly, I find it an interesting language, and my experience with it has been kind of fun - but I can't think of anything it does that most other programming languages don't do better.
"but I can't think of anything it does that most other programming languages don't do better."
What do you mean by that? Io is slow and does not have the extensive libraries that are present in other languages. However, as a pure prototype oo language, it is second to none.
Schemers have not only appreciated exception handling, they have generalized control transfer to a first-class operation. The last 20 years of PL research in Scheme have only been about control semantics, to the point of abuse.
E.g. if you mostly do webapp backends, write a ray tracer in Javascript. If you're a systems programmer, write a blog on AppEngine. Make a screensaver. Make an iPhone app. Etc etc.