Compiling Elisp

Elisp can be byte compiled to what is known as the emacs virtual machine.
I may write more about this in the future; for now you might start reading this emacswiki page; and of course the elisp info pages.
As always, you can also go directly to the source; in this case mainly the code in bytecomp.el, disass.el and bytecode.c.

In principle, byte compiled code should run faster (maybe 2x, 3x?) than interpreted code.
In my limited experience, the speed-up gained by byte compiling my code has been disappointingly modest (usually < 2x); it may well be that I need to adjust my coding style to get the most out of byte compilation. Chris Wellons has written an article about writing faster Elisp.

In recent versions of emacs (since version 28?), byte compiled code may be further natively compiled into (platform dependent) machine language.
I believe the method used is the one describe in Bringing GNU Emacs to Native Code by A. Corallo, L. Nassi, & N. Manca.

Currently this page is mostly just a place holder. But the next section is worth taking a look at.

Byte Compiling to Find Errors

Even if your code is fast enough for your purposes, you can still benefit from habitually byte compiling your code.
This is because byte-compile-file warns about many more errors than either check-parens, or load-file will catch.

I find this check so useful that I routinely do it, using a command like this:

(defun ph/this-file-load (compile?)
  "Load the file the current buffer is visiting.
Runs `check-parens' first, then `load-file'.
when COMPILE? given, also run `byte-compile-file'."
  (interactive "P")
  (ph/check-parens);  See below, but you can simply use check-parens
  (minibuffer-message  "Check parens okay")
  (if (not (buffer-file-name))
      (error  "Cannot load.  Current buffer is not visiting a file")
    (and   ;; and here used to control flow
     (buffer-modified-p)
     (y-or-n-p "Save buffer before loading?")
     (save-buffer)
     )
    (load-file (buffer-file-name))
    (when compile?
      (byte-compile-file (buffer-file-name))
      (display-buffer "*Compile-Log*")
      )))

As a slight refinement I use a customized version of check-parens which ignores and file content occuring after "#@00".
"#@00" is a documented (albeit not encouraged) way to comment out the bottom half of a file.
I find it useful to put unfinished code snippets underneath a #@00.
For example.

(defun foo ()
   (message "hello world")
)

#@00 <-- anything after this is ignored by load-file and byte-compile-file

(defun turing-machine-halts? (turing-machine)
  (let ((Alan   (car turing-machine))
        (Turing (cdr turing-machine))
        )
   (with-temp-buffer
   ;;  Still thinking about the right way to do this...
   ;;  Got so confused I forgot to balance parens!
   )
load-file and byte-compile-file will skip anything after the 4 bytes #@00, but check-parens will not. I find it convenient to define a wrapper which does.
(defun ph/check-parens ()
  "Like `check-parens', but ignore text after a skip to rest of file sequence."
  (interactive)
  (let ((point-ori (point)))
    (save-excursion
      (save-restriction
        (save-match-data
          (goto-char (point-min))
          (when (search-forward (string ?# ?@ ?0 ?0) nil t)
            (when (< (point) point-ori)
              (minibuffer-message  "Elisp skip-rest-of-file-mark found above current point.")
              )
            (narrow-to-region (point-min) (point))
            )
            (check-parens)
            )))))
Seems like a lot of code just to do such a simple thing, but I find it useful.
As a concept check, it might be useful to think about why the above code uses
(search-forward (string ?# ?@ ?0 ?0) nil t)
instead of simply
(search-forward "#@00" nil t);  Not gonna work...

docstring wider than 80 characters warning

By default byte compiling warns if you have a docsting longer than 80 characters.
(defun my/search-forward-for-thing ()
  "Search forward from point for an object which could be a macro name or a variable name or maybe a function name or else a gadget name."
  (...)
)
Byte compiling this will produce a docstring wider than 80 characters warning; as it rightly should. Breaking the docsting up into several lines will not only silence the warning, but usually improve readability as well.
(defun my/search-forward-for-thing ()
  "Search forward from point for object.

The object could be:
  - a macro name
  - a variable name
  -a function name
  -a gadget name
"
  (...)
)

Reasonable use of cl-defun or cl-defstruct can produce a docsting wider than warning

Unfortunately, reasonable use of common lisp inspired constructs including cl-defun and cl-defstruct can also cause this warning.
An example I encountered was:
(cl-defun ph/grep-buffer/aux (search-forward-function
                              query  highlight-matches?
                              &key (new-buf-name (concat "grep:" (buffer-name) ":" query)))
  "Create new buffer for QUERY,
grab lines matching QUERY by the criterion of SEARCH-FORWARD-FUNCTION
and put them in a new buffer with the matching part highlighted."
  (...)
)
Byte compiling this produces a docstring wider than 80 characters warning, even though the docstings I provides do not include any long lines.
In fact the same warning is produced even when there is no docstring given!
(cl-defun ph/grep-buffer/aux (search-forward-function
                              query  highlight-matches?
                              &key (new-buf-name (concat "grep:" (buffer-name) ":" query)))
  ;; No docstring here, but byte compiling will stil generate a docstring wider than error.
  (...)
)
I would call this behavior a bug on the part of the byte compiler. In fact, a bug report has been filed regarding this problem and perhaps someday will be fixed.

The warning is triggered by documentation automatically generated by cl-defun, but this is not evident when viewed using describe-function which yields this output:

ph/grep-buffer/aux is a Lisp closure in ‘ph-grep-buffer.el’.

(ph/grep-buffer/aux SEARCH-FORWARD-FUNCTION QUERY HIGHLIGHT-MATCHES\?
&key (NEW-BUF-NAME (concat "grep:" (buffer-name) ":" query)))

For more information see the manuals.

Create new buffer for QUERY,
grab lines matching QUERY by the criterion of SEARCH-FORWARD-FUNCTION
and put them in a new buffer with the matching part highlighted.

[back]
Showing no lines longer than 80! So what’s the problem? I’m not completely sure, but the value returned by the function documentation gives a strong hint.
(documentation 'ph/grep-buffer/aux)
;; returns
"Create new buffer for QUERY,
grab lines matching QUERY by the criterion of SEARCH-FORWARD-FUNCTION
and put them in a new buffer with the matching part highlighted.

(fn SEARCH-FORWARD-FUNCTION QUERY HIGHLIGHT-MATCHES\\? &key (NEW-BUF-NAME (concat \"grep:\" (buffer-name) \":\" query)))"
The final line is indeed longer than 80 characters.

It is a special line parsed (but not shown) by describe-function to indicate calling conventions for functions and especially macros. For more information see the elisp info pages on "Function Documentation".

Workaround: file local adjustment of byte-compile-docstring-max-column

For the time being, the workaround is to change the value of byte-compile-docstring-max-column to a length longer than the default of 80 characters. One could do this globally with setq, but this would affect all source files. I would not want to do that because overall I think this warning is useful. (even if the default length of 80 may be a bit too strict)

A better way is to use the file local variable concept to limit the effect to just the source file in which the problem occurs. One can use the special first line of the file to set byte-compile-docstring-max-column to a large enough value.

For example, in my particular case I use:

;;; ph-grep-buffer.el ---  -*- lexical-binding: t; byte-compile-docstring-max-column: 115 -*-
As the first line of file ph-grep-buffer.el.
Where I selected the value of 115 to be just long enough to prevent the warning for my function ph/grep-buffer/aux.

This file local adjustment to byte-compile-docstring-max-column will not affect warnings when compiling other source files, but certainly will prevent potential warnings regarding other docstings in ph-grep-buffer.el.

Even so, I still try to keep docsting lines within 80 character.
The command what-cursor-position (default binding C-x =) is useful to see what column point is on.