Any Emacs package developer worth their salt knows the difference between a
defvar and defcustom. These two comprise the vast majority of variable
definitions in Elisp code, but there's a third child, the defconst. While
regular variables and customizable variables only really differ when it comes to
Emacs' customize system, constants differ in loading logic in a subtle but
important way.
When a defvar is evaluated, the value specified is assigned to the variable
only if the previous value was void (if the variable wasn't defined yet).
Evaluating a defconst, on the other hand, always sets the symbol's value to
the (new) given value. This becomes most relevant when a package is upgraded
after having been loaded in Emacs. Any variables defined by the package will
retain their old values until Emacs is restarted, whereas constants will be
updated to their new values.
In a sense, somewhat ironically, Elisp constants are the least constant of all
variables. Rest assured though, they were given this name for a reason. This
behaviour is indeed suited for storing values that should be constant. Here's a
simple use-case which arose for us in sx.el.
The StackExchange API requires that we provide filters to specify which
information we want to receive. Of course, we were storing these filters in
variables and then using that information while printing the question.
The problem with this approach would only be seen after an upgrade. Lets say we
decide to also display a question's score. Without a doubt, we'd change the
above to something like this.
Now the user upgrades sx.el, tries to run it again, and gets hit on the face
with an error!
sx-browse-filter is still using the old value, so the question score is not
returned by the API. That means .score is nil and number-to-string throws an
error. Changing the defvar to defconst was all we needed to prevent this
problem.
If you're wondering why you've never run into such an issue, that's because
package.el used to have another bug, which would never load new package
versions upon upgrade. That has been fixed in 25.1—packages are now reloaded
on upgrade—so you should ensure your package won't run into new problems by
making proper use of constants.
Simply put, you should defconst whenever there are functions or macros in a
package which rely on the variable having that specific value (kind of like a
proper constant). This way you'll know you never have old values hanging around.
What's a defconst and why you should use it
05 Jan 2015, by Artur Malabarba.Any Emacs package developer worth their salt knows the difference between a
defvar
anddefcustom
. These two comprise the vast majority of variable definitions in Elisp code, but there's a third child, thedefconst
. While regular variables and customizable variables only really differ when it comes to Emacs'customize
system, constants differ in loading logic in a subtle but important way.When a
defvar
is evaluated, the value specified is assigned to the variable only if the previous value was void (if the variable wasn't defined yet). Evaluating adefconst
, on the other hand, always sets the symbol's value to the (new) given value. This becomes most relevant when a package is upgraded after having been loaded in Emacs. Any variables defined by the package will retain their old values until Emacs is restarted, whereas constants will be updated to their new values.In a sense, somewhat ironically, Elisp constants are the least constant of all variables. Rest assured though, they were given this name for a reason. This behaviour is indeed suited for storing values that should be constant. Here's a simple use-case which arose for us in sx.el.
The StackExchange API requires that we provide filters to specify which information we want to receive. Of course, we were storing these filters in variables and then using that information while printing the question.
The problem with this approach would only be seen after an upgrade. Lets say we decide to also display a question's score. Without a doubt, we'd change the above to something like this.
Now the user upgrades
sx.el
, tries to run it again, and gets hit on the face with an error!sx-browse-filter
is still using the old value, so the question score is not returned by the API. That means.score
is nil andnumber-to-string
throws an error. Changing thedefvar
todefconst
was all we needed to prevent this problem.If you're wondering why you've never run into such an issue, that's because
package.el
used to have another bug, which would never load new package versions upon upgrade. That has been fixed in 25.1—packages are now reloaded on upgrade—so you should ensure your package won't run into new problems by making proper use of constants.Simply put, you should
defconst
whenever there are functions or macros in a package which rely on the variable having that specific value (kind of like a proper constant). This way you'll know you never have old values hanging around.Tags: style, package, emacs-25, emacs,
Automate a package's group and version number »
« Asynchronous package upgrades with Paradox
Related Posts
It’s Magit! And you’re the magician! in package
Emacs 25 is out! What are the new features and what were my predictions in emacs-25
validate.el: Schema validation for Emacs-Lisp in package
Content © 2019, All rights reserved. Icons under CC3.0.