* doc/lispref/functions.texi (Defining Functions): Document it.
* lisp/subr.el (function-alias-p): New function (bug#53178).
By contrast, in programs that manipulate function definitions for other
purposes, it is better to use @code{fset}, which does not keep such
records. @xref{Function Cells}.
+@end defun
+
+@defun function-alias-p object &optional noerror
+Use the @code{function-alias-p} function to check whether an object is
+a function alias. If it isn't, this predicate will return
+non-@code{nil}. If it is, the value returned will be a list of symbol
+representing the function alias chain. For instance, if @code{a} is
+an alias for @code{b}, and @code{b} is an alias for @code{c}:
+
+@example
+(function-alias-p 'a)
+ @result{} (b c)
+@end example
+
+If there's a loop in the definitions, an error will be signalled. If
+@var{noerror} is non-@code{nil}, the non-looping parts of the chain is
+returned instead.
@end defun
You cannot create a new primitive function with @code{defun} or
\f
* Lisp Changes in Emacs 29.1
++++
+** New function 'function-alias-p'.
+This predicate says whether an object is a function alias, and if it
+is, the alias chain is returned.
+
+++
** New variable 'lisp-directory' holds the directory of Emacs's own Lisp files.
(lambda ()
,@body)))
+(defun function-alias-p (func &optional noerror)
+ "Return nil if FUNC is not a function alias.
+If FUNC is a function alias, return the function alias chain.
+
+If the function alias chain contains loops, an error will be
+signalled. If NOERROR, the non-loop parts of the chain is returned."
+ (declare (side-effect-free t))
+ (let ((chain nil)
+ (orig-func func))
+ (nreverse
+ (catch 'loop
+ (while (and (symbolp func)
+ (setq func (symbol-function func))
+ (symbolp func))
+ (when (or (memq func chain)
+ (eq func orig-func))
+ (if noerror
+ (throw 'loop chain)
+ (error "Alias loop for `%s'" orig-func)))
+ (push func chain))
+ chain))))
+
;;; subr.el ends here
(should (equal (ensure-list :foo) '(:foo)))
(should (equal (ensure-list '(1 2 3)) '(1 2 3))))
+(ert-deftest test-alias-p ()
+ (should-not (function-alias-p 1))
+
+ (defun subr-tests--fun ())
+ (should-not (function-alias-p 'subr-tests--fun))
+
+ (defalias 'subr-tests--a 'subr-tests--b)
+ (defalias 'subr-tests--b 'subr-tests--c)
+ (should (equal (function-alias-p 'subr-tests--a)
+ '(subr-tests--b subr-tests--c)))
+
+ (defalias 'subr-tests--d 'subr-tests--e)
+ (defalias 'subr-tests--e 'subr-tests--d)
+ (should-error (function-alias-p 'subr-tests--d))
+ (should (equal (function-alias-p 'subr-tests--d t)
+ '(subr-tests--e))))
+
(provide 'subr-tests)
;;; subr-tests.el ends here