Introducing Names: practical namespaces for Emacs-Lisp10 Dec 2014, by Artur Malabarba.
A little over a month ago, I released a package called Names, designed for mitigating Emacs' namespace issue. Before I even had a chance to announced it, it made a bit of a splash on r/emacs, which I've taken to mean that people are interested. I've been holding off on this post until I had a couple of Names-using packages under my belt, so I could actually speak from experience as opposed to expectation, and that's finally the case.
Names aims to provide an implementation of namespaces in Emacs-Lisp with four guiding principles:
- Actually useful and easy to grasp.
- Support any function, macro, or special-form available in
emacs-lisp, even the ones defined by you or a third party.
- No-surprises, well-tested, and with clearly stated limitations.
eval-last-sexp(also known as C-x C-e). Integration with other developing tools are under way.
Why a namespace package?
The lack of actual namespaces in elisp is a recurring topic in the Emacs community. The discussion is long and beyond the scope of this post, so I'll refer those interested to Nic Ferrier's great essay on the subject and to a concise explanation by Jon Snader as well.
In short, Emacs takes the approach of prefixing every symbol name with the name of the package. This successfully avoids name clashes between packages, but it quickly leads to code that's repetitive and annoying to write. The links above mentions many shortcomings of this approach, but this code-cluttering repetition of the package name has always bothered me the most. It makes the code longer and more tiresome to read
See this example from package.el. The word “package” is repeated 7 times in a 10-line function.
What does Names do?
It doesn't change this approach, nor does it try to revolutionize Emacs or reinvent packages. Names fully adheres to Emacs conventions and is completely invisible to the end-user, it simply gives you (the developer) a convenient way of writing code that adheres to this standard.
Here's what the code above would look like inside a namespace.
define-namespace is a macro. At compilation, it expands to generate the exact
same code as the original, thus being completely invisible to the user.
How reliable is it?
I'll forgive you for being sceptical, wrapping your entire package in a macro sounds risky. Rest assured, Names is very smart in what it does, and it strives to avoid surprises.
Furthermore, it features a thorough test suite which leverages off other well-tested packages to the respectable sum of 244 tests. Of course, the number by itself has no objective meaning, but it shows that I'm commited to making it as reliable and robust as possible. To prove I mean business, the last two packages I pushed to Melpa already make use of it. And if that's not enough, I just got news that shell-switcher has joined the party and seems to be passing all tests.
In terms of availability, it's on GNU Elpa, so it's a safe dependency for any
Emacs starting with
And how do I use it?
If you learn better by example, you can have a quick look at this short dummy package available on the repo or, for real world packages, see camcorder.el or aggressive-indent. In any case, it's important to check the Readme for the most up-to-date instructions but here's the gist of it:
namesas a dependency. A typical header will contain
- Write all code inside the
define-namespacemacro, preceded by an
;;;###autoloadcookie. The first argument of the macro is the prefix which will be applied to all definitions.
providestatements go outside the macro.
- Inside the macro, instead of using
;;;###autoloadcookies, use the
And that's pretty much it. Just write your code without prefixing every symbol with the package name, and Names will take care of that for you.
1. Every definition gets namespaced
Any definitions inside will have the prefix prepended to the symbol given. So the code
essentially expands to
2. Function calls and variables are namespaced if defined
This is best explained by example. This code:
expands to this code:
infinitesymbol gets namespaced only as a function name, not when it's used as a variable. That's because Names knows that
foo-infiniteis not a defined variable.
- The symbol
::infiniteis not namespaced, because it had been protected with
something-elseis not namespaced, because it is not a locally defined function, so it must be external.
3. Quoted forms are not namespaced.
Whenever a form is not meant for evaluation, it is left completely untouched.
The most significant example of this are lists and symbols quoted with a simple
'foo). These are regarded as data, not code, so you'll have to
write the prefix explicitly inside these quoted forms.
Some examples of the opposite:
- Symbols quoted with a function quote (e.g.
#'foo) are regarded as function names, and are namespaced as explained in item 2. Remember you should use the function quote for functions anyway.
- Comma forms inside a back-tick form (e.g.
`(nothing ,@(function) ,variable)) are meant for evaluation and so will be namespaced.
But is it all worth it?
Absolutely! Like I said, I've already written two packages using Names, and I had a blast! Of course, my opinion is biased. But I can say with all honesty that it's an absolute delight to not need to worry about all those prefixes.
I invite people to try it out. If you do, make sure you
in your init file. This will enable integration with
eval-last-sexp. I've already got news that shell-switcher
has made the conversion, and
alchemist seems to be on the way.