Skip to content
Print

Should We Really Study Other Languages?

4
Mar
2008

The practice of learning multiple languages has really become dogma in the modern developer community.  Everyone knows that you should study different languages, different paradigms and various techniques for accomplishing the same thing.  Why?  The canonical answer is that it helps you grow into a better programmer in your primary language.  After all, if you know how to compose functions in Lisp, naturally that must make it easier to design flexible systems in Java.  I would beg to differ.

I must admit, I used to be a card-carrying member of the “one language per year” club.  I used to push myself and other developers to get their feet wet in alternative languages, even ones which had no practical application (I learned Ruby back when it was just a toy for Asian folks).  Recently though, I’ve been coming more to the conclusion that perhaps this frenetic dash to learn the most languages might not be the “ultimate answer” after all.  A commenter on Reddit relates a story which is (I believe) quite applicable to the subject:

When I was in college, one of the jobs I had was a TA for an intro programming class. For one of their projects, I was asked to whip up a kind of web browser “shell” in Java. The basic idea was to make a browser that would be highly extendable by students, while freeing them from worrying about the overall rendering framework.

Now, the first language that I learned was Smalltalk, which has historically been relatively design-pattern-free due to blocks and whatnot, and I had only learned Java as an afterthought while in college, so I coded in a slightly unorthodox way, making use of anonymous inner classes (i.e., shitty lambdas), reflection, and the like. I ended up with an extremely loosely coupled design that was extremely easy to extend; just unorthodox.

When I gave it to the prof, his first reaction, on reading the code, was…utter bafflement. He and another TA actually went over what I wrote in an attempt to find and catalog the GoF patterns that I’d used when coding the application. Their conclusion after a fairly thorough review was that my main pattern was, “Code well.”

You may laugh (I did), but I can’t tell you how much code I’ve had to work with which reminds me of this tale.  Developers these days pick up patterns and best-practices from dozens of languages and try to apply them to a language for which they are ill suited.  Consider the following code:

public class SortUtils {
    public static <T> List<T> mergeSort(final List<T> list) {
        return new Object() {
            private final List<T>[] divided = divide(list);
 
            public List<T> run() {
                return merge(mergeSort(divided[0]), mergeSort(divided[1]));
            }
        }.run();
    }
 
    public static <T> List<T>[] divide(final List<T> list) {
        if (list.size() == 0) {
            return new List<T>[] {new ArrayList<T>(), new ArrayList<T>()};
        } else if (list.size() == 1) {
            return new List<T>[] {list, new ArrayList<T>()};
        } else {
            return new Object() {
                // this part doesn't really work, it's just illustrative
                private final T first = list.remove();
                private final T second = list.remove();
                private final List<T>[] sub = divide(list);
 
                public List<T>[] run() {
                    return new List<T>[] {new ArrayList<T>() {
                        {
                            addAll(sub[0]);
                            add(first);
                        }
                    }, new ArrayList<T>() {
                        {
                            addAll(sub[1]);
                            add(second);
                        }
                    }};
                }
            }.run();
        }
    }
 
    public static <T> List<T> merge(final List<T> left, final List<T> right) {
        if (left.size() == 0) {
            return right;
        } else if (right.size() == 0) {
            return left;
        } else {
            if (left.get(0) < right.get(0)) {
                return new ArrayList<T>() {
                    {
                        add(left.remove(0));
                        addAll(merge(left, right));
                    }
                };
            } else {
                return new ArrayList<T>() {
                    {
                        add(right.remove(0));
                        addAll(merge(left, right));
                    }
                };
            }
        }
    }
}

I know what you’re thinking: Whoever wrote this is a sick, sick programmer.  Actually I wrote it, but that’s beside the point…  :-)

The point is that taking knowledge gained in one language and directly applying it to another is almost never the right approach.  This isn’t how you sort a list in Java, it’s how you would do it in ML, or maybe even Lisp.  By trying to apply functional idioms directly to an object-oriented language, I’ve accomplished code which does two things.  First, it’s unmaintainable.  No sane-minded Java developer is ever going to be able to take this code and make incremental improvements.  Second (and just as important), it is extremely slow.  Pure-functional languages are written in such a way as to make function calls, recursion and immutable data very performant.  Java just doesn’t work like that.  This code is creating objects left and right, recursing and copying data back and forth so many times its a wonder the whole machine doesn’t crash.

What’s ironic is even with all my efforts, I still couldn’t eliminate mutable data and sequential statements entirely.  Java’s data structures are mutable by design, something which makes it very inefficient to try to do things immutably.  Java’s APIs just aren’t built to comply with expression-based algorithms, something which is an absolute must when working with immutable data.

Throwing away Java’s utter lack of functional constructs like cons (::) and pattern matching, this code is still horrible because it doesn’t follow the Java idioms.  Not only is the Java language built to perform better when used imperatively, but the constructs are such that the code is more concise and maintainable.  Would it have killed readability to use a loop?  Hardly.  In fact, considering the mess we got when trying to avoid imperative constructs, it’s difficult to imagine things getting less readable.

This is certainly an extreme example, no right-minded developer would ever try to do something like this in the real world, but the point remains.  The same problems can be seen even in examples like applying Java’s for-loop idiom for iterating over arrays in Ruby.  Language-specific idioms are important, and we only cripple ourselves if we ignore them.

So at the end of the day, does this really mean we should stop learning new languages?  Absolutely not.  As “Pragmatic Dave” famously pointed out, learning a new language opens our mind to new ways of approaching problems.  It’s not so much how the code is written as much as gaining a deeper insight into the process of solving the problem.  Learning Scala has helped me refine my problem-solving abilities, allowing me to more effectively approach tasks in any language.

However, I think that this “perspective improvement” is a bit over-stressed.  Yes, problem solving is an important skill, one which should be refined through experience with multiple approaches, but I don’t think it’s as critical as many people make it out to be.  I know some really phenomenal developers who only know one language.  Could they be better for learning another?  Probably, but the point is they’re doing just fine right now.  Being multi-lingual is not critical, and as my facetious example illustrates, it can be very harmful.

In the end, the best reason for learning a new language stands unchallenged and unassailable: it’s fun.  I derive a great deal of satisfaction from learning how to do things in a new language, applying my old skills to new tools.  At the end of the day, I don’t really care whether I’m learning anything important to my career.  This may be the case, but the only thing which really matters to me is the challenge of the new puzzle, a new riddle to crack.  I certainly believe that most good developers will derive the same enjoyment, and as long as they keep their idioms straight, I’m perfectly content with that.

Comments

  1. I agree, but from a slightly different angle. I tend to stick with programming languages that are syntactically and conceptually similar, simply because it reduces the amount of mental overhead that I have to maintain between languages. Learning how other languages use patterns, however, can be useful.

    ncloud Tuesday, March 4, 2008 at 9:38 am
  2. Nice strawman… What’s the point of coming up with an obfuscated, piece of code that (as the comment says) doesn’t even work? If you had dredged this out of a real code base that was written by certifiably sane developers, then… well would still be anecdotal, and it would just mean that you might want to look for slightly more mature developers for your team.

    murphee Tuesday, March 4, 2008 at 9:54 am
  3. I do have a different/better anecdote which shows the nastiness of cross-applied idioms, but I discounted it because it’s not dramatic enough. In essence:

    public static LinkedList getPeople() {
    LinkedList back = new LinkedList();
    int size = 0;
    Connection conn = …
    try {

    for (size = 0; res.next(); ++size) {
    back.add(new Person(res.get(0));
    }
    } catch(Throwable t) {}
    return back;
    }

    The developer who wrote this no longer works on the project, but I assure you he is quite competent and is capable of writing some very powerful stuff. The problem is he’s a C developer shoe-horned into writing Java code. He may be a fine developer, but by dragging C idioms into the mix, he’s just making life difficult.

    Daniel Spiewak Tuesday, March 4, 2008 at 11:05 am
  4. Let me offer another argument.
    Are you a Java Developer or a Software Engineer that uses Java?

    The first is a one trick pony, might be able to keep a job for a while. The second is an “expert” that solves problems (also collects a much higher salary). Besides the hubub about right tool for the job, by being a software engineer, you are not locked into one way of doing things (professionally or mentally).

    Sure, by just learning a language you can still be a long way from being an expert in it’s best practices and idioms. The syntax for a new language should take a day or two max to learn, the other stuff is what takes a while. However, you can “know enough” to decide if you want to take it further.

    Paul Davis Tuesday, March 4, 2008 at 11:38 am
  5. Very true. I didn’t even mention the fact that consultants almost *require* a knowledge of multiple languages and technologies, not for the learning experience but for the flexibility. I can’t imagine being a software consultant and not knowing half a dozen main-stream languages, the market is just too competitive for that. It’s also worth remembering that a lot of modern projects are implemented in more than one language (I think the hip term for this is “polyglot”).

    Daniel Spiewak Tuesday, March 4, 2008 at 11:45 am
  6. Upon reading your article I feel it is inconsistent in it’s argumentation. You state in your introduction that you disagree with the point that learning another language helps you to better at your primary language. This would be all fine, if you didn’t spend a half of the article writing why you shouldn’t apply the coding style you learn in your new language _directly_ in your old one.

    This makes you conclude that learning a good language is good for problem solving, but that problem solving isn’t really that important because you know good programmers who only know one language who might be better had the known more.

    I think I can agree with you as far as saying that you shouldn’t code Java as you would code lisp, which I would think was pretty obvious. I’m not tempted to ask myself if it’s really worth it to study another language, just because I can’t write PHP exactly like I would write Haskell.

    That said I think your article was a nice read hadn’t it been for the heading a lead paragraph, that seems to be a little too polemic to me.

    Have fun.

    Jonas Tuesday, March 4, 2008 at 2:09 pm
  7. @Jonas

    Ok, you got me. I’m admittedly terrible at writing introductions, especially for articles where I’m still hashing out the logic for myself.

    With that said, I think the spirit of the introductory paragraph is still in line with the rest of the article, it’s just very poorly phrased. My point was that people tend to over-extend the impetus for learning new languages to encompass cross-language idioms when what they really want to describe is abstract problem solving. Because generic “problem solving” is difficult to define, I avoided using the term in the introduction, leading to some of the inconsistency.

    Daniel Spiewak Tuesday, March 4, 2008 at 2:14 pm
  8. Before I got to the end, I too was thrown off by the beginning and middle. My comment was going to be “so because you can write shitty code by blindly applying idioms and style from different languages in different paradigms, you throw out learning new languages all together?”

    The end clears it up that in fact, that’s not what you meant, but the beginning right up until “Absolutely not” made me feel that way.

    The rest of it was a good illustration of what not to do when learning a new language though.

    Sammy Larbi Wednesday, March 5, 2008 at 5:31 am
  9. The merge function would be more readable by using the conditional operator. In fact I’d go as far as saying its more readable than “standard” java. Having said that the performance doesn’t look too good even after re-writing.

    public static List merge(final List left, final List right) {
    return left.size() == 0 ? right :
    right.size() == 0 ? left :
    new ArrayList() {
    {
    add(left.get(0)

    Mark Grant Tuesday, April 8, 2008 at 11:14 am

Post a Comment

Comments are automatically formatted. Markup are either stripped or will cause large blocks of text to be eaten, depending on the phase of the moon. Code snippets should be wrapped in <pre>...</pre> tags. Indentation within pre tags will be preserved, and most instances of "<" and ">" will work without a problem.

Please note that first-time commenters are moderated, so don't panic if your comment doesn't appear immediately.

*
*