Git Product home page Git Product logo

emacs-lisp-style-guide's Introduction

The Emacs Lisp Style Guide

Role models are important.

– Officer Alex J. Murphy / RoboCop

This Emacs Lisp style guide recommends best practices so that real-world Emacs Lisp programmers can write code that can be maintained by other real-world Emacs Lisp programmers. A style guide that reflects real-world usage gets used, and a style guide that holds to an ideal that has been rejected by the people it is supposed to help risks not getting used at all — no matter how good it is.

The guide is separated into several sections of related rules. I’ve tried to add the rationale behind the rules (if it’s omitted, I’ve assumed that it’s pretty obvious).

I didn’t come up with all the rules out of nowhere; they are mostly based on my extensive experience of using Emacs and creating/maintaining Emacs packages, feedback and suggestions from members of the Emacs Lisp community, and various highly regarded Emacs Lisp programming resources, such as “GNU Emacs Lisp Reference Manual”.

The guide is still a work in progress; some sections are missing, others are incomplete, some rules are lacking examples, some rules don’t have examples that illustrate them clearly enough. In due time these issues will be addressed — just keep them in mind for now.

Please note, that the Emacs developers maintain a list of coding conventions and tips too.

You can generate a PDF or an HTML copy of this guide using Pandoc.

Table of Contents

Source Code Layout & Organization

Nearly everybody is convinced that every style but their own is ugly and unreadable. Leave out the “but their own” and they’re probably right…

– Jerry Coffin (on indentation)

  • Use spaces for indentation. No hard tabs.

In practical terms this means you should add the following to your Emacs config:

(setq-default indent-tabs-mode nil)

An even better idea would be to force the use of spaces using .dir-locals.el in each of your Emacs Lisp projects.

((emacs-lisp-mode
  (indent-tabs-mode nil)))
  • For regular functions, vertically align function arguments.
;; good
(format "%s %d"
        something
        something-else)

;; bad
(format "%s %d"
  something
  something-else)
  • If the first argument is on a new line, align it with the function’s name.
;; good
(format
 "%s %d"
 something
 something-else)

;; bad
(format
  "%s %d"
  something
  something-else)
  • Some forms are special, they take 1 or more “special” arguments followed by a “body” (an arbitrary number of arguments where only the final return value matters), e.g. =if=, let, with-current-buffer, etc. The special arguments should either be on the same line as the form’s name or be indented by 4 spaces. The body arguments should be indented by 2 spaces.
    ;; good
    (when something
      (something-else))
    
    ;; bad - four spaces on the body
    (when something
        (something-else))
    
    ;; bad - aligned like a regular function
    (when
     something
     (something-else))
        
  • Note that the “then” clause of an if form is a special argument, indent it by 4 spaces.
    ;; good
    (if something
        then-clause
      else-clause)
    
    ;; bad
    (if something
      then-clause
      else-clause)
        
  • Vertically align let bindings.
    ;; good
    (let ((thing1 "some stuff")
          (thing2 "other stuff"))
      ...)
    
    ;; bad
    (let ((thing1 "some stuff")
      (thing2 "other stuff"))
      ...)
        
  • Use Unix-style line endings. (*BSD/Solaris/Linux/OSX users are covered by default, Windows users have to be extra careful.)
    • If you’re using Git you might want to add the following configuration setting to protect your project from Windows line endings creeping in:
    bash$ git config --global core.autocrlf true
        
  • If any text precedes an opening bracket((, { and [) or follows a closing bracket(), } and ]), separate that text from that bracket with a space. Conversely, leave no space after an opening bracket and before following text, or after preceding text and before a closing bracket.
    ;; good
    (foo (bar baz) quux)
    
    ;; bad
    (foo(bar baz)quux)
    (foo ( bar baz ) quux)
        
  • Place all trailing parentheses on a single line instead of distinct lines.
    ;; good; single line
    (when something
      (something-else))
    
    ;; bad; distinct lines
    (when something
      (something-else)
    )
        
  • Use empty lines between top-level forms.
    ;; good
    (defvar x ...)
    
    (defun foo ...)
    
    ;; bad
    (defvar x ...)
    (defun foo ...)
        

    An exception to the rule is the grouping of related =def=s together.

    ;; good
    (defconst min-rows 10)
    (defconst max-rows 20)
    (defconst min-cols 15)
    (defconst max-cols 30)
        
  • Do not place blank lines in the middle of a function or macro definition. An exception can be made to indicate grouping of pairwise constructs as found in e.g. =let= and cond.
  • Where feasible, avoid making lines longer than 80 characters.
  • Avoid trailing whitespace.
  • Avoid parameter lists with more than three or four positional parameters.
  • Always enable lexical scoping. This must be done on the first line as a file local variable.
    ;;; -*- lexical-binding: t; -*-
        

Syntax

  • Don’t wrap the else clause of an if in a progn (it’s wrapped in progn implicitly).
;; good
(if something
    if-clause
  (something)
  (something-else))

;; bad
(if something
    if-clause
  (progn
    (something)
    (something-else)))
  • Use when instead of (if ... (progn ...).
;; good
(when pred
  (foo)
  (bar))

;; bad
(if pred
  (progn
    (foo)
    (bar)))
  • Use unless instead of (when (not ...) ...).
;; good
(unless pred
  (foo)
  (bar))

;; bad
(when (not pred)
  (foo)
  (bar))
  • Use not instead of null, unless your checking whether something is nil (empty list). Despite its name (null instead of nullp), the function null is mostly meant to be used as a predicate.
;; good
(if (null lst) ...)

(if (or (not foo) something) ...)

;; bad
(if (not lst))

(if (and (null foo) bar) ...)
  • When doing comparisons, keep in mind that the functions <, >, etc. accept a variable number of arguments as of Emacs 24.4.
;; Preferred
(< 5 x 10)

;; Old
(and (> x 5) (< x 10))
  • Use t as the catch-all test expression in cond.
;; good
(cond
  ((< n 0) "negative")
  ((> n 0) "positive")
  (t "zero"))

;; bad
(cond
  ((< n 0) "negative")
  ((> n 0) "positive")
  (:else "zero"))
  • Use (1+ x) & (1- x) instead of (+ x 1) and (- x 1).
  • Use with-eval-after-load instead of eval-after-load.
;; good
(with-eval-after-load "foo"
  (bar)
  (baz))


;; bad
(eval-after-load "foo"
  '(progn
     (bar)
     (baz)))

Naming

The only real difficulties in programming are cache invalidation and naming things.

– Phil Karlton

  • Use lisp-case for function and variable names.
;; good
(defvar some-var ...)
(defun some-fun ...)

;; bad
(defvar someVar ...)
(defun somefun ...)
(defvar some_fun ...)
  • Prefix top-level names with the name of the library they belong to in order to avoid name clashes.
;; good
(defun projectile-project-root ...)

;; bad
(defun project-root ...)
  • Prefix unused local (lexically scoped) variables with _.
;; good
(lambda (x _y) x)

;; bad
(lambda (x y) x)
  • Use -- to denote private top-level definitions (e.g. =projectile–private-fun=).
  • The names of predicate methods (methods that return a boolean value) should end in a p if it’s a single-word name and a -p if it’s a multi-word name (e.g., evenp and buffer-live-p).
;; good
(defun palindromep ...)
(defun only-one-p ...)

;; bad
(defun palindrome? ...) ; Scheme style
(defun is-palindrome ...) ; Java style
;; good
(defface widget-inactive ...)

;; bad
(defface widget-inactive-face ...)

Macros

  • Don’t write a macro if a function will do.
  • Create an example of a macro usage first and the macro afterwards.
  • Break complicated macros into smaller functions whenever possible.
  • A macro should usually just provide syntactic sugar and the core of the macro should be a plain function. Doing so will improve composability.
  • Prefer syntax-quoted forms over building lists manually.

Functions

  • Use =lambda=s for local bindings and function calls, not for hooks or global variables. Define named functions for the latter, they aid readability and customizability.
;;; Good
(mapcar (lambda (x) (or (car x) "")) some-list)
(let ((predicate (lambda (x) (and (numberp x) (evenp x)))))
  (funcall predicate 1000))

;;; Bad - Define real functions for these.
(defcustom my-predicate (lambda (x) (and (numberp x) (evenp x)))
  ...)
(define-key my-keymap (kbd "C-f")
  (lambda () (interactive) (forward-char 1)))
(add-hook 'my-hook (lambda () (save-some-buffers)))
  • Never hard quote a lambda, it impedes byte-compilation.
;;; Good
(lambda (x) (car x))

;;; Ok, but redundant.
#'(lambda (x) (car x))

;;; Bad
'(lambda (x) (car x))
  • Don’t wrap functions in anonymous functions when you don’t need to.
;; good
(cl-remove-if-not #'evenp numbers)

;; bad
(cl-remove-if-not (lambda (x) (evenp x)) numbers)
  • Use a sharp quote (#') when quoting function names. It’s a good hint for the byte-compiler, which will warn you if the function is undefined. Some macros can also behave differently otherwise (like cl-labels).
;; good
(cl-remove-if-not #'evenp numbers)
(global-set-key (kbd "C-l C-l") #'redraw-display)
(cl-labels ((butterfly () (message "42")))
  (funcall #'butterfly))

;; bad
(cl-remove-if-not 'evenp numbers)
(global-set-key (kbd "C-l C-l") 'redraw-display)
(cl-labels ((butterfly () (message "42")))
  (funcall 'butterfly))

Macro Declarations

  • Always declare the debug-specification, this tells edebug which arguments are meant for evaluation. If all arguments are evaluated, a simple (declare (debug t)) is enough.
  • Declare the indent specification if the macro arguments should not be aligned like a function (think of defun or with-current-buffer).
(defmacro define-widget (name &rest forms)
  "Description"
  (declare (debug (sexp body))
           (indent defun))
  ...)

Loading and Autoloading

  • Always end each library file with a provide statement and an appropriate comment (the provide statement will allow dependent libraries to use require).
(provide 'foo)

;;; foo.el ends here
  • Always load library dependencies with require, rather than load or load-library (the former is idempotent, while the others can result in multiple evaluations).
  • Include autoload cookies for mode definitions and commonly-used user-facing functions and commands (i.e. setup functions and commands that could be bound to a key). Conversely, do not provide autoload cookies for global variables or internal functions.
;;; good
;;;###autoload
(define-derived-mode foo-mode ...)

;;;###autoload
(define-minor-mode foo-minor-mode ...)

;;;###autoload
(defun foo-setup () ...)

;;; bad
;;;###autoload
(defun foo--internal () ...)

;;;###autoload
(defvar foo-option)
  • Do not provide autoload cookies for non-definition top-level forms (autoloading a library should never alter the behavior of a user’s configuration). The single exception: auto-mode-alist can be altered for new major modes.
;;; good
;;;###autoload
(add-to-list 'auto-mode-alist '("\\.foo\\'" . foo-mode))

;;; bad
;;;###autoload
(foo-setup)

Lists

  • Use dolist instead of calling the same s-exps over different variables:
;;; good
(dolist (hook '(prog-mode-hook text-mode-hook))
  (add-hook hook 'turn-on-column-number-mode)
  (add-hook hook 'turn-off-line-number-mode)
  (add-hook hook 'linum-mode))

;;; bad
(add-hook 'prog-mode-hook 'turn-on-column-number-mode)
(add-hook 'prog-mode-hook 'turn-off-line-number-mode)
(add-hook 'prog-mode-hook 'linum-mode)
(add-hook 'text-mode-hook 'turn-on-column-number-mode)
(add-hook 'text-mode-hook 'turn-off-line-number-mode)
(add-hook 'text-mode-hook 'linum-mode)
  • Use seq-do or dolist instead of mapcar if you don’t intend to concatenate the result.
;;; good
(font-lock-add-keywords nil (mapcar 'downcase list-of-crazy-cased-words))
(seq-do 'load list-of-files-to-load)

;;; bad
(mapcar 'load list-of-files-to-load)
  • Use dolist instead of calling seq-do over a lambda. Reserve seq-do for single function calls.
;;; good
(dolist (map (list c-mode-map c++-mode-map))
  (define-key map "\C-c\C-c" 'compile))

;;; bad
(mapc
  (lambda (map) (define-key map "\C-c\C-c" 'compile))
  (list c-mode-map c++-mode-map))

Comments

Good code is its own best documentation. As you’re about to add a comment, ask yourself, “How can I improve the code so that this comment isn’t needed?” Improve the code and then document it to make it even clearer. – Steve McConnell

  • Endeavor to make your code as self-documenting as possible.
  • Write heading comments with at least three semicolons.
  • Write top-level comments with three semicolons if it represents a heading, otherwise use two semicolons.
  • Write comments on a particular fragment of code before that fragment and aligned with it, using two semicolons.
  • Write margin comments with one semicolon.
  • Always have at least one space between the semicolon and the text that follows it.
;;; Frob Grovel
;; This is where Frob grovels and where Grovel frobs.

;; This section of code has some important implications:
;;   1. Foo.
;;   2. Bar.
;;   3. Baz.

(defun fnord (zarquon)
  ;; If zob, then veeblefitz.
  (quux zot
        mumble             ; Zibblefrotz.
        frotz))
  • Comments longer than a word begin with a capital letter and use punctuation. Separate sentences with two spaces.
  • Avoid superfluous comments.
;; bad
(1+ counter) ; increments counter by one
  • Keep existing comments up-to-date. An outdated comment is worse than no comment at all.

Good code is like a good joke - it needs no explanation. – Russ Olsen

  • Avoid writing comments to explain bad code. Refactor the code to make it self-explanatory.

Do, or do not. There is no try. – Yoda

Comment Annotations

  • Annotations should usually be written on the line immediately above the relevant code.
  • The annotation keyword is followed by a colon and a space, then a note describing the problem.
  • If multiple lines are required to describe the problem, subsequent lines should be indented as much as the first one.
  • Tag the annotation with your initials and a date so its relevance can be easily verified.
(defun some-fun ()
  ;; FIXME: This has crashed occasionally since v1.2.3. It may
  ;;        be related to the BarBazUtil upgrade. (xz 13-1-31)
  (baz))
  • In cases where the problem is so obvious that any documentation would be redundant, annotations may be left at the end of the offending line with no note. This usage should be the exception and not the rule.
(defun bar ()
  (sleep 100)) ; OPTIMIZE
  • Use TODO to note missing features or functionality that should be added at a later date.
  • Use FIXME to note broken code that needs to be fixed.
  • Use OPTIMIZE to note slow or inefficient code that may cause performance problems.
  • Use HACK to note “code smells” where questionable coding practices were used and should be refactored away.
  • Use REVIEW to note anything that should be looked at to confirm it is working as intended. For example: REVIEW: Are we sure this is how the client does X currently?
  • Use other custom annotation keywords if it feels appropriate, but be sure to document them in your project’s README or similar.

Docstrings

Emacs is famous for the breadth, depth, and ubiquity of its documentation. By taking the time to write docstrings in your package, you are helping to continue that tradition!

  • Begin with a terse, complete sentence. Use imperative language. For example, prefer “Verify” over “Verifies”, and “Check” over “Checks”.
  • When a function takes arguments, mention what the arguments do, whether they are required, and so on. Describe the arguments in UPCASE, and order them as they are used.
  • Always capitalize “Emacs”.
  • Do not indent subsequent lines of a documentation string. This looks nice in the source code, but looks bizarre when users view the documentation.
;; good
(defun goto-line (line &optional buffer)
  "Go to LINE, counting from line 1 at beginning of buffer.
If called interactively, a numeric prefix argument specifies
LINE; without a numeric prefix argument, read LINE from the
minibuffer..."
...)

;; bad
(defun goto-line (line &optional buffer)
  "Go to LINE, counting from line 1 at beginning of buffer.
   If called interactively, a numeric prefix argument specifies
   LINE; without a numeric prefix argument, read LINE from the
   minibuffer..."
  ...)

;; also bad
(defun goto-line (line &optional buffer)
  "Go to LINE, counting from line 1 at beginning of buffer.
   If called interactively, a numeric prefix argument specifies
 LINE; without a numeric prefix argument, read LINE from the
 minibuffer..."
  ...)

Tools

  • Use checkdoc to check for docstring style issues.
    • Many people in the Emacs community use checkdoc with Flycheck.
  • Use package-lint to check packages before submission to repositories such as MELPA.
    • See the package-lint README about integration with Flycheck.

Existential

  • Be consistent. In an ideal world, be consistent with these guidelines.
  • Use common sense.

Contributing

Nothing written in this guide is set in stone. It’s my desire to work together with everyone interested in Emacs Lisp coding style, so that we could ultimately create a resource that will be beneficial to the entire Emacs community.

Feel free to open tickets or send pull requests with improvements. Thanks in advance for your help!

License

http://i.creativecommons.org/l/by/3.0/88x31.png This work is licensed under a Creative Commons Attribution 3.0 Unported License

Spread the Word

A community-driven style guide is of little use to a community that doesn’t know about its existence. Tweet about the guide, share it with your friends and colleagues. Every comment, suggestion or opinion we get makes the guide just a little bit better. And we want to have the best possible guide, don’t we?

Cheers,
Bozhidar

emacs-lisp-style-guide's People

Contributors

ambrevar avatar bbatsov avatar dgutov avatar fuco1 avatar lgirvin avatar malabarba avatar mwfogleman avatar shosti avatar skeeto avatar sviridov avatar xiongtx avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

emacs-lisp-style-guide's Issues

Remind people to define a version number defconst

Besides the ;; Version: comment, it's useful for packages to define their version numbers as variables.
Something like the following should be enough.

(defconst PACKAGE-version "1.3" "PACKAGE's version number.")

Testing conventions

Hi and thanks for this awesome style guide. It truly helps adding standards to this community and is also a place to discover best practices by established Elisp seniors.

One thing I miss from all this is testing conventions. It seems the community is just recently investing more time in CI pipelines with testing, coverage reports and so on. From my personal opinion, though, this topic is still not widely discussed nor standardized. Things like:

  • What is a good practice for naming tests?
  • When its good practice to create a wrapper macro to add functionality to ERT?
  • Should we use test-helper.el and if yes, what is the recommended practices?
  • How to assert failures with temp files without actually leaving them on the file system?
  • etc (I think that even if we start this small it will grow bigger with the community input)

Maybe this should be a NEW style guide that could first recommend this one, but I think this will help a lot too.

Anyway, if this feels out of place feel free to simply close it. Once again, thanks for all your work!

Consistency between seq-do, seq-map, mapc, and mapcar

Use seq-do or dolist instead of mapcar if you don’t intend to concatenate the result.

Hi! I'm curious about the wording of this guideline. Suggesting dolist makes sense to me, but:

  1. Why seq-do over mapc? seq isn't immediately available without loading seq, but mapc is.

  2. If it's because seq-do is more generic, why offer mapcar as an alternative instead of the similarly generic seq-map?

Thanks for your time!

Proposal: prefer #' (sharp quote) when quoting function names

When quoting symbols to access their function definitions, prefer the use of sharp quotes. This allows the bytecompiler to check if the function exists, issuing a warning just like it would when calling an undefined function.

This would change the anonymous function example.

(cl-remove-if-not #'evenp numbers)

Sharp quoting has become a lot more relevant with the introduction of lexical scoping.

(defun foo ()
  :global)

(cl-flet ((foo () :local))
  (list (funcall 'foo) (funcall #'foo)))
;; => (:global :local)

Use uninterned symbols in expanded let-forms of macros

Use uninterned symbols in expanded let-forms of macros if the values of these symbols are for macro-internal use only.

;; bad:
(defmacro i-interned (&rest body)
  (declare (debug (body)))
  `(let ((i 1))
     (progn
       (message "Macro internal value of i: %s" i)
       ,@body)))

;; good:
(defmacro i-uninterned (&rest body)
  (declare (debug (body)))
  (let ((i (make-symbol "i")))
    `(let ((,i 1))
       (progn
	 (message "Macro internal value of i: %s" ,i)
	 ,@body))))

(let ((i 0))
  (i-interned
   (message "Value of i: %s" i)))

(let ((i 0))
  (i-uninterned
   (message "Value of i: %s" i)))

Output in the *Messages* buffer:

Macro internal value of i: 1
Value of i: 1
Macro internal value of i: 1
Value of i: 0

Not sure about dissuading scheme-style predicates

The style guide recommends against ending predicate functions in ?, but some high-quality libraries (such as dash.el) use that style extensively and I don't really see a good reason to avoid it (the -p predicate functions always seem like something of an anachronism). I guess the bigger question is whether the style guide should always follow the internal Emacs coding guidelines (internally I think -p is always used). It's worth noting that there are already some recommendations that are not at all in line with what's done internally in the Emacs source code, such as avoiding hard tabs. Anyways, I'd just be interested in hearing people's thoughts on this.

Collaborate?

Hi Bozihdar,

I just discovered this repo. I think something like this is definitely needed, since, e.g. I see Steve Purcell having to repeatedly give a lot of the same feedback to new package developers. I recently started https://alphapapa.github.io/emacs-package-dev-handbook/. It seems like we're covering some of the same ground. Do you think we should collaborate in some way, or do you think we're addressing different issues? I will certainly be linking to this repo in it. :)

Automatic alignment?

I'm wondering about all the alignment rules--since Emacs Lisp will almost always be edited from within Emacs, it seems to me that the correct alignment is always "however Emacs automatically aligns it". I think there should definitely be some rules on using declare and other ways to adjust automatic indentation (there seems to be some confusion surrounding best practices around that). I'm not even sure the other alignment rules would be necessary in that case, although they might be nice to keep as a reference.

;;; is for headings only

In Emacs Lisp by convention three or more semicolons are treated as headings.

From (elisp)Comment Tips

`;;;'
     Comments that start with three semicolons, `;;;', should start at
     the left margin.  We use them for comments which should be
     considered a "heading" by Outline minor mode.  By default,
     comments starting with at least three semicolons (followed by a
     single space and a non-whitespace character) are considered
     headings, comments starting with two or fewer are not.
     Historically, triple-semicolon comments have also been used for
     commenting out lines within a function, but this use is
     discouraged.

     When commenting out entire functions, use two semicolons.

outline-minor-mode and others use this like this.

;;; heading
;;;; subheading
;;;;; subsubheading
;;;;;; and so on

;; comment
;; continued
(code)

Separate sentences with _two spaces_

The "Comments" section says

Separate sentences with one space.

This is in violation of the Emacs default settings and common coding convention. The default value of sentence-end-double-space is t and most elisp code follows this behavior. It allows unambiguous distinction between sentence endings and other uses of the period.

Yes, there is a debate whether double spacing is good or bad style and the article does link to the wikipedia page about it. But this is simply not the place to have that discussion. The Emacs default settings have decided the discussion as far as common coding conventions for elisp are concerned. It seems therefore rather annoying and pointless to put personal preferences there. (The arguments against double spacing are largely exclusive for proportional fonts, which nobody uses for coding anyway.)

Therefore the comment should be changed to "Separate sentences with two spaces" or if the author really insists on personal preferences over common coding conventions then it should at least be removed.

Why 2 spaces rather than tabs?

No reasons are given for the recommendation to use two spaces rather than single tabs in indentation. At least two questions must be answered: (1) Why prefer spaces to tabs and (2) Why prefer multiples of 2 spaces?
Addressing the second question: Arbitrary numbers are always suspicious; in this case the result is an amount of indentation which looks good with some choices of font sizes, printing options, etc. and looks poor under other circumstances.
Addressing the first question: Since the display width of tabs is easily adjustable, e.g. to the width of 2 spaces when desirable, and this functionality is not available with spaces, why would one not always prefer tabs?
Note also that the recommendation of using multiples of 2 spaces conflicts with the recommendation to align with the first argument of forms. A logical alternative might be to use tabs to align to the level of the form followed by spaces to align with the first argument.

Proposal: prefer setf (generalized variables) over setter functions

This one is probably controversial. Emacs 24.3 took setf out of the cl package (at the same time renaming it to cl-lib) and introduced it to the Emacs Lisp core as generalized variables (gv). Many of the "places" in Emacs that hold values can be mutated with the setf family of functions. For example,

(setf somevar :foo)
(setf (point) (point-max))
(setf (buffer-name) "*scratch*")
(setf (cdr somelist) (list 2 3 4))

setq is a vestigial feature leftover from Emacs Lisp's dynamic scoping days. It's no longer conceptually a wrapper for set, and "set quoted" [doesn't really make sense in lexical scope](http://random-state.net/files/nikodemus-cl-faq.html#set-setq-and-setf----whats-the-difference-which-one-should-
i-use).

The big advantage with generalized variables is that APIs no longer need to include a bunch of special setter functions for every possible place. The getter and its natural setf complement cover everything. It also composes with the other generalized setters (rotatef, incf, etc.).

On the other hand, this change only happened in the very latest stable release (24.3, March 2013). Even though it's over a year old, many people still aren't quite up to date. The change was made in a not entirely backwards-compatible way: in Emacs 24.3 you're not supposed to (require 'cl) in new code, but you can use setf without it. Prior to this you had to require cl (even if just at compile time) before using setf. So perhaps there needs to be more time before it's appropriate to prefer generalized veriables.

Prefer `nil` for empty lists over `()` or `'()`

There are essentially 5 ways to "initialize" a list

(let (results)
  (--each ... (push x results)))

(let ((results))
  (--each ... (push x results)))

(let ((results nil))
  (--each ... (push x results)))

(let ((results ()))
  (--each ... (push x results)))

(let ((results '()))
  (--each ... (push x results)))

Personally I use 2 and 3 and prefer 2 if there are multiple bindings at the same time

(let ((x 1)
      (y 2)
      (results)
      (z 3))
  (--each ... (push x results)))

Having it wrapped in the parens sort of signifies to me it's a list. A nil there wouldn't hurt though, I'm just lazy.

I was hoping there would be some way to distinguish () and nil for example for the purpose of analysis but they both appear as nil to the reader, so meh.

Currently left out topic: Use lexical binding.

Nowdays one should use lexical binding for library programming in Elisp. Optimization is better with lexical binding.

The new Section should contain the following warning:
If one uses a special variable from another library in a function one must have either a top-level defvar for that variable in the file where it is used or a require for the other library at top-level. Otherwise let in functions can go terribly wrong for variables that are declared special in other libraries. The lexical binding of that variables is not visible in functions called within the let-form.

Body on the same line as a conditional form

I'm wondering if there should be a convention for two other kinds of cases:

(when something do-something)

versus

(when something
  do-something)

or, as another case to be discussed separately:

(if foo bar baz)

versus

(if foo
    bar
  baz)

One might want to do that to save on lines when the condition and the body are short enough.

Should it be allowed, recommended, to avoid, forbidden, up to the writer ?

org-mode?

Hey, I kinda feel this guide would serve emacs users better in a format that would require no additional package as dependency!

Just a thought. :)

Which is better "when-and" layout?

Hello, and sorry for my poor English.

So I often write some when-and statements, which is better written?

(when (and (sth1) (sth2))
  (body))
(when (and (sth1)
           (sth2))
  (body))

[Suggestion]: Minimize additions to list variables

Add one element when appropriate.
e.g.
Instead of adding multiple entries to auto-mode-alist:

(add-to-list 'auto-mode-list ("\\.inp\\'" . apdl-mode))
(add-to-list 'auto-mode-list ("\\.dat\\'" . apdl-mode))
(add-to-list 'auto-mode-list ("\\.ans\\'" . apdl-mode))
(add-to-list 'auto-mode-list ("\\.mac\\'" . apdl-mode))

Add a single element:

(add-to-list 'auto-mode-list ("\\.\\(?:ans\\|dat\\|inp\\|mac\\)\\'" . apdl-mode))

The same should be considered for any global variable which is checked frequently.

Use descriptive keyword argument instead of `t` when boolean flag is expected

For example, functions which expects 5 arguments, all of which are t can get very confusing with calls like (foo t nil t nil t). It is not obvious what to do.

Recently I've been naming such arguments with descriptive names and then pass :argument-name keyword as a value. For example

(defun update (&optional force)
   "Update the list of values. If FORCE is non-nil, invalidate cache first.")

You would then call it (update) or (update :force) instead of (update t).

I think there is very little confusion possible over keyword-argument-functions and keyword-as-flags usage, especially when you can consult the documentation in about 1 second.

What do you think people?

Co-editors

@lunaryorn @purcell @Bruce-Connor @dgutov I've been pretty busy lately which has stalled the progress on this project (which I feel is very important long-term). You're all Emacs Lisp experts and can definitely help move the project forward. Are any of you willing to join as co-editors?

Determining arguments to interactive functions

Is there any prevailing wisdom on when to use the (interactive (list ...)) form over the body code (setq arg-1 (or arg-1 (get-default))? Personally I prefer (and more often see) the former, but I've realized I have no good reasoning either way.

Proposal: Don't use anonymous functions as hooks

i.e. instead of this:

(add-hook 'foo-mode-hook (lambda () (do-something 10)))

use this:

(defun my-foo-mode-hook ()
  (do-something 10))

(add-hook 'foo-mode-hook 'my-foo-mode-hook)

(These probably aren't great name examples). The advantage of the latter is that if the hook function is changed everything will work out, whereas re-doing add-hook with a changed anonymous function will result in both the new and old anonymous functions being run.

Proposal: Put macro definitions in their own section at the top of files

The Emacs byte-compiler has some really annoying gotchas around definition order. For instance, the following will cause runtime errors when byte-compiled, but won't usually show up when you're developing since the macro will probably already have been evaluated:

(defun my-function () 
  (my-macro ...))

(defmacro my-macro (...) ...)

In order to avoid this problem, it seems like best practice to always define macros before functions, perhaps in their own section. I guess we could have some broader guidelines around library organization as well (e.g. defcustoms first, then macros, then functions or something along those lines).

Let's put transient caches/state/files/crap in .emacs.d/.cache

I've been cleaning up my config and doing some gitignore grooming and I came to the realization I had over 100 ignore rules in there :O.

Packages should put their caches and files holding state in some "centralized" directory. I propose (locate-user-emacs-file ".cache"). This is an analogy of $XDG_CACHE_HOME which points to $HOME/.cache by default (base dir spec).

It should really be enforced by emacs proper, but for now we can at least do it this way. Ideas?


This is what I end up with. Note that some directories have multiple files under them. (oh, and I autosave scratch buffers there too, I lost my data too many times now :))

The t/:else in `cond`s

Personally, I use the :otherwise keyword as found in haskell and some other (functional) languages. :else should be reserved for if/else chains, so I agree :else is not a good choice there. But how about other keywords? It once happened to me that I had to test if the parameter was t literally (which you have to do with comparing symbols), so t in the branch might lead to confusion with case (where you are matching the symbol itself).

But that's a very rare situation so in practice it shouldn't make much difference. Still, I like to use descriptive arguments anywhere where t is expected.

Add section on loading

There should probably be a section on loading. Here are some rules I'm thinking of:

  1. Always include a provide statement at the end of every library.
  2. Always use require instead of load for library files.
  3. Always include an autoload cookie for functions and global variables that are commonly accessed.

Anything else?

Naming convention for boolean variables

Style guide suggest to name functions that return booleans with p or -p for "predicate", but what convention should be used for such variables, like feature-enabled or feature-enabled-p. These variables are used in predicate position in if or when, yet those aren't functions, so I'm a bit confused.

Proposal: Always use lexical scope in new code

Lexical scope was introduced in Emacs 24. All new Emacs Lisp code should begin with a local variable statement setting the file to lexical scope.

;;; foo.el --- Foo the bars -*- lexical-binding: t; -*-

Lexical scope has safer and cleaner semantics (local assignments aren't visible in callees, scopes are predictable at compile time), allows for additional checks by the compiler (free variables must be declared as global variables, variables aren't just opaque symbols), and has better performance (stack-oriented storage). All new code should take full advantage of it. Global variables are still dynamic, so there are no disadvantages to using lexical scope.

progn along with if

I see that progn is discouraged in the style guide. I am thinking about how is the following scenario handled.

If there is more than one statement to be executed if the condition is true and otherwise.

Comment guidelines conflict with Comment Tips from the Elisp reference

Tthe rule to use three semicolons for top-level comments conflicts with the Emacs Lisp reference.

According to Comment Tips two semicolons should be used for top-level comments between functions:

Comments that start with two semicolons, ‘;;’, should be aligned to the same level of indentation as the code. […] We also normally use two semicolons for comments outside functions.

Three semicolons are used for headings (emphasis mine):

Comments that start with three semicolons, ‘;;;’, should start at the left margin. […] We also use them sometimes for comments that are between functions—whether to use two or three semicolons depends on whether the comment should be considered a “heading” by Outline minor mode. By default, comments starting with at least three semicolons (followed by a single space and a non-whitespace character) are considered headings, comments starting with two or fewer are not.

That's also the style used within Emacs, for instance in font-lock.el.

I do not think that we should deviate from the Emacs Lisp references without need.

Should there be guidelines for preserving global state?

Elisp has a lot of mutable global state. Some of it is highly shared. And it is very easy to modify global, highly shared state inadvertently. This includes point, mark, narrowing, match data, current buffer, selected window, selected frame, and who knows what else.

For example, calling (looking-at "[ \t]") to check if we are on whitespace clobbers match data. If this is done in a function, the caller has to wrap its invocation in a (save-match-data) if match data is important.

Proposal:

  • If your function is not specifically intended to modify global shared state, preserve it by wrapping your function body in the appropriate (save-*) or (with-*) macros.
  • If you do modify global shared state, at a minimum, document the fact; ideally, document how you modify it.
  • If you accept function arguments and expect them to modify global shared state, document your expectations. If they are called in a modified shared state context, document that context.

Naming function arguments

Dear emacs-lisp-style-guide,

I've always been afraid of naming things. Things began to go wrong when as a child I named my pet hamster C-x C-( # and all the kids in the school's vim user group made fun of me. A year later I named my pet chimpanze "grandma" and got no present for christmas! I had to steal some tinsel off the tree and take it to school pretending it was a new brand of "soft, linear slinky". It's just so difficult! The uncertainty and arbitrariness involved always make me feel like I've made the wrong choice and It has always been an endless source of mental anguish. That is why I am so glad to have a resource such as this, so that now when I make a bad choice I can simply point at someone else and claim "They made me do it!", just like that murder trial they put me through.

Ever since I began using your guide my life has been transformed. I now feel dynamic and vivacious, even vigorous. My wife tells me I've grown several inches, an unexpected delight at my ripe old age of 117! and I'm getting taller too!

One nagging issue I still have trouble with, which this admirable compandium of sound advice has provided no guidance on thus far, is the question of properly naming a function argument when writing a higher-order function. Should I use a suffix like -func or -f? should I use a descriptive action name like score-of or compare? perhaps there is an even better way?

Anxiously Awaiting your Advice,

Kind regards,
Trepidatious in Trinidad

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.