2023-08-21, updated: 2024-03-12

Tested with Nyxt -.

Tags: engineering, lisp.

Why not Elisp to build Nyxt?

Why not Elisp to build Nyxt?

By John Mercouris

In our righteous endeavor to ascend the ethereal heavens, behold the grandeur of the computational Tower of Babel, crafted with utmost devotion. We have formed a sacred unity of Lisp atop C, and Assembler upon the hallowed foundation of logic gates.

The Tower of Babel - Pieter Bruegel the Elder, 1563

As we transcend the heavenly threshold of the Kármán line, we stand at the sacred crossroads of destiny. Reverently, we ponder: Shall we invoke the divine power of Elisp, or shall we embrace the heavenly wisdom bestowed by the celestial realms of Lisp (Common Lisp)?

The answer of course as always is it depends. We'll cover our philosophical, and logical reasons about why we chose Common Lisp over Elisp.

A Single reference implementation

The first problem with Elisp (and with many other languages) is that only a single reference implementation exists. This usually means that quirks of the reference implementation are codified as "standard" behavior.

This leads to other significant problems. Frequently, undefined behavior is not specified by a specification. Frequently, support for different architectures and environments is limited. Frequently, development is led by a single organization… etc.

In short, because other languages are confined to (typically) a single reference implementation, they are inflexible and poorly specified!

Note: other Elisp implementations did exist, but they were never compatible with each other, nor were they based on a unified specification.

A bad reference implementation

Perhaps a single implementation is acceptable if you are willing to target a single architecture, environment, or system. However, the one that comes with Elisp is not suited for our purposes. Elisp on Emacs is simply too slow to do the analysis and computational work that exists in Nyxt. We would have to offload many of our operations to external processes, libraries, or functions. Which brings us to our next point…

Poor CFFI (C Foreign Function Interface)

Elisp has awful CFFI as compared to Common Lisp. Emacs has never had a good way to connect to shared libraries. Therefore, even if we did want to offload some of our computationally heavy work to other libraries, it would be an absolute chore to do so. On the other hand, in Common Lisp, it is a breeze.

No concurrency

Elisp is still stuck in the 1990s. There is no good concurrency model. Everything, and I mean everything runs on a single thread. This is simply unacceptable for a modern day browser.

No packages

Packages are a rather primitive function of most languages. However, in Elisp, they are nowhere to be found. Everything is in a global namespace. You can imagine this leads to a myriad of problems and conventions.


In short, Elisp was designed with a very specific purpose, and a single reference implementation. For this, it is well suited. It is however not a general purpose programming language that can be adopted for any task. Doing so would be shoehorning it into a job it was never meant to do.

Though we (at Atlas) are all Emacs users and lovers, we recognize that we must use the right tool, and for us, that is Common Lisp.

Did you enjoy this article? Register for our newsletter to receive the latest hacker news from the world of Lisp and browsers!