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:
Practical
Actually useful and easy to grasp.
Complete
Support any function, macro, or special-form available in
emacs-lisp, even the ones defined by you or a third party.
Robust
No-surprises, well-tested, and with clearly stated limitations.
Debuggable
Support edebug, find-function/ variable/ face,
eval-defun, and 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 twopackages 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 24.1.
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:
List names as a dependency. A typical header will contain
Write all code inside the define-namespace macro, preceded by an
;;;###autoload cookie. The first argument of the macro is the prefix which
will be applied to all definitions. require and provide statements go
outside the macro.
Inside the macro, instead of using ;;;###autoload cookies, use the
:autoload keyword.
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:
Note how:
The infinite symbol gets namespaced only as a function name, not when it's
used as a variable. That's because Names knows that foo-infinite is not a
defined variable.
The symbol ::infinite is not namespaced, because it had been protected with
::.
something-else is 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
quote (e.g. '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 (require 'names-dev)
in your init file. This will enable integration with edebug, find-function,
eval-defun, and eval-last-sexp. I've already got news that shell-switcher
has made the conversion, and alchemist seems to be on the way.
Introducing Names: practical namespaces for Emacs-Lisp
10 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:
emacs-lisp
, even the ones defined by you or a third party.edebug
,find-function
/variable
/face
,eval-defun
, andeval-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
24.1
.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:
names
as a dependency. A typical header will containdefine-namespace
macro, preceded by an;;;###autoload
cookie. The first argument of the macro is the prefix which will be applied to all definitions.require
andprovide
statements go outside the macro.;;;###autoload
cookies, use the:autoload
keyword.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:
Note how:
infinite
symbol gets namespaced only as a function name, not when it's used as a variable. That's because Names knows thatfoo-infinite
is not a defined variable.::infinite
is not namespaced, because it had been protected with::
.something-else
is 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 quote (e.g.
'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:
#'foo
) are regarded as function names, and are namespaced as explained in item 2. Remember you should use the function quote for functions anyway.`(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
(require 'names-dev)
in your init file. This will enable integration withedebug
,find-function
,eval-defun
, andeval-last-sexp
. I've already got news that shell-switcher has made the conversion, andalchemist
seems to be on the way.Tags: namespaces, names, emacs,
New on Elpa and in Emacs 25.1: let-alist »
« Tab Completion for Prose
Related Posts
Nameless, less is more in namespaces
Automate a package's group and version number in names
Content © 2019, All rights reserved. Icons under CC3.0.