Thursday, November 12, 2009

Javascript and Emacs Lisp

Warning: if you don't subscribe to the One True Religion, this probably won't interest you.

With my recent affair with Elisp and the development in GNOME where some influential people are dropping C in favour of Javascript for GUI programming (we may wonder how many kilolines of boiler-plate C code they've churned out to reach that conclusion), I couldn't help thinking about replacing Elisp with Javascript in Emacs.

First a bit of introduction. Emacs is an incredibly old and incredibly smart text editor with a smallish C core and most of the intelligent stuff written in a Lisp dialect called Emacs Lisp. Lisp is a very flexible language that intermingles data and code. Making a system built on it extensible is relatively straight-forward. This is probably the main reason behind the success of Emacs, the editor has been extended in literally thousand of directions over the years. If you read my previous blog post, I'm using what nowadays is dubbed aspect-oriented programming to hack a built-in Emacs Lisp module.

It's my impression that even within the Emacs community there are few people who think Emacs Lisp is a great language. It's not Common Lisp, it has some weird idioms and as a small Lisp dialect it still lacks the simplicity of Scheme.

However, weird idioms aside, in my humble opinion the big problem with Emacs Lisp is momentum. When Emacs was started, Lisp was hot. People were thinking that Lisp would be the future. Back in those days, they even had hardware that ran Lisp! The mind boggles. Lisp was an obvious choice for a dynamic extension language.



Today much has changed and few people are using Lisp. The obvious choice for a dynamic extension language today is something else. Basic, Python, Lua, etc. Or Javascript.

A die-hard Lisp fan would think the solution is another Lisp, but the official GNU Scheme embeddable language Guile looks pretty dead to me. While learning Lisp is a worthwhile goal that will definitely teach you some lessons, I think there's good reason why most programmers aren't writing parenthesized lists all day long.

By switching to Javascript, Emacs would once again be ahead of the curve. And the Emacs maintainers would be relieved of having to maintain a language interpreter with its related problems. For instance, and I don't know if things have changed recently, the garbage collector in Emacs used be pretty basic. Probably because when it just sort of works, nobody wants to mess with it anymore, people naturally want to focus on writing the best editor possible.

I don't think the idea would fly, however, for several reasons. There is an enormous body of Lisp code out there for Emacs. And since Lisp is the extension language for Emacs, everybody contributing to it is a Lisp hacker. It's hard to see how this actually pretty large group of people making up the community would accept anything else than a Lisp. And in the past, even proposals to reform Emacs Lisp or switch to other Lisp dialects have all failed.

To add to that, Javascript has a bad reputation, especially among people who haven't done any client-side web development lately.

Thus I think the only way Javascript in Emacs could happen meaningfully is by targeting the interpreter: replace the Emacs Lisp interpreter with a Javascript engine like Spidermonkey or V8 and a bridge that translates the Lisp and makes Lisp symbols available to Javascript and vice versa. So all Lisp code would run unaltered, and everyone can continue writing Lisp as they do today.

The aim would be less code to maintain in Emacs and the benefit of a well-maintained optimizing engine that is getting faster every day, with several independent free ones to choose from.

I think you could maybe sell that idea to the Emacs maintainers. A project like CEDET that replicates the code parsing engines of modern IDEs would definitely benefit from a speedup.

As a side-effect, it would then be possible to extend Emacs with pure Javascript. And a growing horde of web developers will suddenly find it much easier to extend Emacs.

I had a very brief look at the C source of Emacs, and it looks like you would have to rewrite and port maybe 10-20.000 lines of C code. So I think it's doable.

Of course, there are several open questions. How hard is it to do the translation? Can a Javascript engine actually run Lisp-translated-to-Javascript code efficiently? Is it a good idea at all or just a futile exercise in chasing the latest fad of the day? I am not sure. Javascript has been around for a decade and the web is still growing as a platform, so I don't think it qualifies as a fad. And GNOME is currently betting its future on it.

Another option would be to just embed the Javascript engine on top of the current core. As far as I know, that has been tried already with Python, and didn't work out. I don't think people will use it unless it is bundled with Emacs and sitting right in the core. After all, most customizations start out with a little hack building on existing code in Emacs.

Wednesday, November 11, 2009

Django shell in Emacs

Yet another recipe. One of the neat things with Python is its REPL, the interactive shell. When working with Django models, you need to setup a couple of things before you can use the Python shell. Django provides a shell command for doing this, but it makes it difficult to use the built-in Emacs Python REPL.

I was talking to Anders about it the other day when it occurred to me that it could be a quite powerful environment.

The main problem with the Python shell is that it lacks easy reload support. So you start it up, import the module you're writing and run a couple of functions to test it. Discover an error, fix it with Emacs, save, and then you're in trouble because you can't reload the module in the shell. You have to quit the shell, restart it and reimport the module. History helps but it's still silly (well, actually it's a blatantly stupid oversight, maybe in the top 3 of things to fix in Python to speed up development time).

But with a shell integrated in Emacs, I could solve this problem, right? So I set out to write the necessary Elisp. Dump the following in your .emacs, and it should magically work:

;; run Django shell when editing Django Python code

(defun get-file-in-upstream-dir (location filename)
(let* ((dir (file-name-directory location))
(path (concat dir filename)))
(if (file-exists-p path)
path
(if (not (equal dir "/"))
(get-file-in-upstream-dir (expand-file-name (concat dir "../")) filename)))))

(defadvice run-python (before possibly-setup-django-project-environment)
(let* ((settings-py (get-file-in-upstream-dir buffer-file-name "settings.py"))
(project-dir (file-name-directory settings-py)))
(if settings-py
(progn
(setenv "DJANGO_SETTINGS_MODULE" "settings")
(setenv "PYTHONPATH" project-dir)))))

When the Python interpreter is started, the hook above looks for a settings.py file in the parent directories. If one is found, it sets up Django and also sets the PYTHONPATH to the project toplevel.

Use the code with C-c C-z to show interpreter window, C-c C-c to evaluate buffer, C-c C-r to evaluate region, etc. (they're in the Python menu at top).

You'll probably want the following snippet too, it disables the warning that a Python process is still active when you quit Emacs:

(add-hook 'inferior-python-mode-hook
(lambda ()
(set-process-query-on-exit-flag (get-process "Python") nil)))

I think python-mode should do this by itself, but in the end I didn't have the energy to report a bug and fight with the Emacs maintainers.

So did it fix the import problem in Python? Of course not. The shell inside Emacs still can't reimport a module. Sigh. But at least it's easier to test the current module because you can easily evaluate the whole buffer (which works fine).