Homepage: https://www.gnu.org/software/emacs
Author: Stefan Monnier
Define functions by their inliner
This package provides the macro `define-inline' which lets you define functions by defining their (exhaustive) compiler macro. The idea is that instead of doing like defsubst and cl-defsubst (i.e. from the function's definition, guess the best way to inline the function), we go the other way around: the programmer provides the code that does the inlining (as a compiler-macro) and from that we derive the definition of the function itself. The idea originated in an attempt to clean up `cl-typep', whose function definition amounted to (eval (cl--make-type-test EXP TYPE)). The simplest use is for plain and simple inlinable functions. Rather than: (defmacro myaccessor (obj) (macroexp-let2 macroexp-copyable-p obj obj `(if (foop ,obj) (aref (cdr ,obj) 3) (aref ,obj 2)))) Or (defsubst myaccessor (obj) (if (foop obj) (aref (cdr obj) 3) (aref obj 2))) Or (cl-defsubst myaccessor (obj) (if (foop obj) (aref (cdr obj) 3) (aref obj 2))) You'd do (define-inline myaccessor (obj) (inline-letevals (obj) (inline-quote (if (foop ,obj) (aref (cdr ,obj) 3) (aref ,obj 2))))) Other than verbosity, you get the best of all 3 above without their respective downsides: - defmacro: can't be passed to `mapcar' since it's not a function. - defsubst: not as efficient, and doesn't work as a `gv' place. - cl-defsubst: only works by accident, since it has latent bugs in its handling of variables and scopes which could bite you at any time. (e.g. try (cl-defsubst my-test1 (x) (let ((y 5)) (+ x y))) and then M-: (macroexpand-all '(my-test1 y)) RET) There is still one downside shared with the defmacro and cl-defsubst approach: when the function is inlined, the scoping rules (dynamic or lexical) will be inherited from the call site. Of course, since define-inline defines a compiler macro, you can also do call-site optimizations, just like you can with `defmacro', but not with defsubst nor cl-defsubst.