emacs

A Comment on “Multilanguage Programming”

May 3rd, 2008  |  Published in code, column, commentary, emacs, languages, productivity, tools  |  Bookmark on Pinboard.in

A commenter named Nick left a thoughtful response to my post about my “Multilanguage Programming” column. Rather than respond to it with another comment, I thought I’d turn my response into a full posting, as I think Nick’s feedback is representative of how many people feel about the topic.

Nick said:

I would say that instead of spending a lot of time on a conceptually different language it could be more beneficial to study, say, distributed algorithms or software/system architecture principles or your business domain. There is so much knowledge in this world that learning how to code the same thing in, roughly speaking, one more syntax seems like a waste of time. Even paying real attention to what is going on in the cloud computing can easily consume most of one’s spare time.

I think there are assumptions here that are not necessarily true. Specifically, you’re not necessarily learning how to code the same thing in multiple languages; rather, the idea is that by choosing the best language for the task, coding is “just right” for the problem at hand. For example, I know from significant first-hand experience that if you want to write a set of distributed services that support replication, failover, and fault tolerance, the code you’d write to do that in C++ will be extremely different from the code you’d write in Erlang to achieve the same thing (well, actually, you’d be able to achieve far more in Erlang, in far fewer lines of code).

This is about much more than syntax. It’s about facilities, semantics, and trade-offs. If it were just syntax, then that would imply that all languages are equal in terms of expressiveness and capability, which we already know and accept to be untrue.

The cloud computing topic actually provides a good example of why knowing multiple languages can be useful. To use the Google App Engine, for example, you need to develop your applications in Python. What if you don’t know Python? Too bad for you.

From a real life perspective, it takes years or working on nontrivial software to master a language. For example, some people still manage to have only a vague idea of util.concurent — and this is just a small enough (and well explained in the literature) part of Java. How realistic is it to expect that the majority of developers will be able to master multiple languages concurrently?

I disagree that it takes years to master a language. One of the best OO developers I ever worked with was a mechanical engineer who taught himself programming. One of my current coworkers — a relatively young guy — started programming in Erlang only a few months ago, and he’s already writing some fairly sophisticated production-quality code. In 1988, I started using C++; by 1989, I was starting to help guys like Stan Lippman, Jim Coplien, and others correct coding mistakes in their excellent books. I have a BSEE, no formal computer science training whatsoever, and am completely self-taught as far as programming languages go. (The only class I ever had in any computer language was a BASIC class I had to take in 1981.) Two other coworkers started with Python just a few months ago and they do quite well with it at this point. I can cite numerous such examples from throughout my career. I don’t think any of us are super-programmers or anything like that, so if we can do it, I don’t see why it would be a problem for anyone else.

Perhaps you’re falling trap to the “huge language” problem I mentioned in my column. It certainly can take some people many years to master enormous languages like Java and C++, but most languages are simply nowhere near that big.

And who wants to maintain a code base written in widely different languages? Which most likely means multiple IDEs, unit testing frameworks, build systems (hey, not everyone is using even Maven yet), innumerable frameworks etc. And most of the interpreted languages among those are not even likely to run in the same VM. Not to mention the number of jobs asking for non-C++/Java skills.

I use a number of languages daily and I really have no trouble maintaining the code regardless of which language any particular piece happens to be written in, or whether I wrote the code or one of my teammates did. Once you know a language, you know it; switching to it is no more difficult than using your one and only language if you’re a monolingual developer.

You also mention the “multiple IDE” problem. The first draft of my column contained some fairly direct language describing my dislike of IDEs, or more accurately, my dislike of the IDE culture, but Doug Lea suggested I take it out, so I did. The problem is that some folks let the tool drive their solutions, rather than using the tool as a means to developing solutions. I’ve had numerous people tell me they won’t consider using a language unless their IDE fully supports it with Java- or Smalltalk-like refactoring. To me, that’s completely backwards. I’d rather use an extensible editor that can handle pretty much any language, thus letting me develop optimal solutions using the right languages, rather than having a mere editing tool severely limit my choice of possible solutions.

But there are language mavens and there are tool mavens, and they typically disagree. Follow that link and read, as the posting there is incredibly insightful. I am definitely a language maven; languages are my tools. I suspect, though, that Nick and others who raise similar questions to the ones quoted here lean more toward being tool mavens. I’m not passing judgment on either; I’m only pointing out the different camps to help pinpoint sources of disagreement.

As far as unit test frameworks, build systems, and frameworks go, I haven’t ever found any big issues in those areas when using multiple languages. The reason, not surprisingly, is that knowing multiple languages gives you multiple weapons for testing and integration. Ultimately, when you’re used to using multiple languages, you’re used to these kinds of issues and thus they don’t really present any formidable barriers.

And as far as jobs go, the best developers I’ve known throughout my career have been fluent in a number of programming languages, and each of them could work virtually wherever they wanted to. I don’t believe this correlation is mere coincidence.

Curiously enough, this argumentation is hardly ever mentioned. Authors tend to assume that developers are lazy or have nothing else to learn.

I don’t assume developers are lazy. Rather, I think our industry generally has a bad habit of continually seeking homogeneity in platforms, in languages, in tools, in frameworks, etc., and we really, really ought to know better by now. Once you learn to accept the fact that heterogeneity in computing is inevitable — since nothing can do it all, right? — you find yourself able to use that heterogeneity to your advantage, rather than continually battling against it and losing.

Personally, I am planning to look at Scala and probably Erlang but even judging from the number of books on those it’s clear to me that they represent merely a niche market.

Today’s niche market is tomorrow’s mainstream market. Regardless of whether either of those languages continues to grow, learning one or both will make you a better developer than you are today.

Consider the final question I ask in my column:

After all, do any of us really believe we’ve already learned the last programming language we’ll ever need?

I suspect the vast majority of developers would answer “no” to this question. Assuming that’s the case, then if you don’t regularly practice learning new languages, how do you know when you really need to start learning a new one, and how capable will you be of learning that next language when the need arises? The longer you stay with one language, the more isolated you become, typically without even realizing it. Shifting gears gets harder and harder. Then one day you look up and all the interesting work is elsewhere, out of your reach. Is that a position you want to put yourself in?

Elisp

January 24th, 2008  |  Published in code, emacs, emacs-lisp  |  Bookmark on Pinboard.in

Today I saw two blog postings about emacs-lisp, which is unusual given the feeds I pay attention to. I’ve been using emacs since 1985, and so over the years I’ve written more than my share of elisp. I didn’t know anything about Lisp when I started, so I learned by doing, first by just reading other code, then experimenting and adopting more and more patterns and approaches as I came to understand them. Over the years I’ve studied Lisp here and there on my own and so have improved my elisp, I think, but I’d never call myself an expert. I’ve never worked closely with anyone who enjoyed writing elisp as much as I do, so with nobody to bounce ideas off of, I’m sure there’s still much I can learn.

The first posting I saw today is about the proper handling of association lists, or alists. An alist is a list of key/value pairs, and one critical way they’re used in emacs is for the auto-mode-alist, which indicates what editing mode a given file should be set into when it’s visited. The mode is chosen by attempting to matching each key in the alist against the name of the file being visited; when one matches, it treats the associated value as a function and executes it in the file’s buffer. Such functions usually set the editing mode of the buffer. The keys are typically regular expressions that match file suffixes.

The author of that post had been using the aput function to replace elements of the auto-mode-alist with the editing modes he preferred, but recent changes to emacs resulted in aput being moved to the assoc package, so it was no longer directly available for use in the author’s ~/.emacs startup file. The author’s search for a substitute function to use instead resulted in him getting some bad advice about how alists are handled, and his posting explains how things really work.

One obvious way to fix the problem is to simply (require 'assoc), which would load the assoc package and make aput available. The author didn’t to want to do that, probably to avoid dragging in everything else the package defines. So, he instead resorted to using the push function to prepend elements to the auto-mode-alist to indicate his preferred editing modes. As he explains, file loading always searches the alist from head to tail, and so will always find his settings first, even if the same key patterns occur later in the list.

Another way to do it — a more fun way, perhaps — is to write your own version of aput. The code is interesting because it requires you to pass the alist essentially by reference to the function so it can modify it. The second elisp posting I saw today was Steve Yegge’s “Emergency Elisp” tutorial, and he mentions pass-by-reference but doesn’t really say how to do it, so let’s look at a way to do that. Here’s my version of aput:

(defun my-aput (alist key value)
  (let ((al (symbol-value alist))
        cell)
    (cond ((null al) (set alist (list (cons key value))))
          ((setq cell (assoc key al)) (setcdr cell value))
          (t (set alist (cons (cons key value) al))))))

This doesn’t do exactly what the real aput does, since it doesn’t handle the case where a key with a nil value is passed, but that’s not needed for the auto-mode-alist case. The function expects the alist, the key, and the value. As the three cases of the cond statement show:

  1. if the alist is empty, set it to a list consisting only of the new key/value pair;
  2. if we find the key, replace its associated value with the value passed in;
  3. otherwise prepend the new key/value pair to the front of the alist.

The key to making this work, though, is that we don’t really pass the alist. Instead, we pass the symbol for the alist. The symbol is kind of like a reference, in that it lets us get at the value of the alist, which we do in the first line of the function via the symbol-value function. Our first condition tests the alist to see if it’s nil; if so, we set a new alist value for the symbol. Our third condition (which always runs if the first two don’t, since it tests the value of t, which is always true) also sets a new value for the symbol by prepending a new key/value pair onto the current alist value.

To call it, we do this:

(my-aput 'auto-mode-alist "\\.erl\\'" 'erlang-mode)

Note how we quote the auto-mode-alist, so rather than evaluating it and passing its value, we pass just its name, or symbol, effectively giving us pass-by-reference.

Elisp is the primary reason I keep using emacs. It’s amazingly powerful. You can make it do all kinds of editing chores for you. A lot of people today tend to rely on their IDEs, and I even tried to move to Eclipse a few years ago, but I just don’t think there’s any IDE that can match the power and extensibility that elisp gives you. I’m sure I’ll get a few disagreeable comments for that remark, but they’ll almost certainly be from people who don’t know elisp.

Since I’m not an elisp expert, though, my explanation might be off in some way, and it’s probably possible to improve my code. All constructive criticism is welcomed!