1

I have some code that I use in my .emacs file that works with version 25.5 where the definition of windows--sanitize-window-sizes looks something like this:

(defun window--sanitize-window-sizes (frame horizontal) ;; emacs 25.5

That I want to make work both there and in emacs 27.1 where the definition of windows--sanitize-window-sizes looks something like this:

(defun window--sanitize-window-sizes (horizontal) ;; emacs 27.1

So, how do I check in my calling function how many arguments the function expects, what do I write to ask this question, as in:

   (cond
     ((not (fboundp 'window--sanitize-window-sizes))
      t ; no function to call, assume sizes ok
      )
      ((= (max-number-of-arguments 'window--sanitize-window-sizes) 1)
       ;; probably something like (cdr (arguments-accepted 'window--sanitize-window-sizes))
       (window--sanitize-window-sizes size) ; 27.1 expects only size 
       )
      (t
       (window--sanitize-window-sizes frame size) ; 25.5 expects only size 
       )
      )

I presume there is a function I can apply to a symbol that tells me how many arguments are expected (min max) or maybe something more complex to handle &optional and &rest cases.

3 Answers 3

2

2nd Edit: Turns out there is a builtin, func-arity. It works exactly like the lambda-arity included below. Might be worth checking if it's defined in your emacs 25 though.

1st Edit: having re-read your use-case, maybe just do (if (< (string-to-number emacs-version) ... instead.


Not built-in, no. There's help-function-arglist which returns the signature, such as (arg1 &optional arg2 &rest args).

Luckily, EmacsWiki has a parser for this, relevant code extracted from

https://www.emacswiki.org/emacs/parser-fn.el

(require 'help-fns)

(defun lambda-arity (function)
  "Return minimum and maximum number of args allowed for FUNCTION.
FUNCTION must be a symbol whose function binding is a lambda expression
or a macro.
The returned value is a pair (MIN . MAX).  MIN is the minimum number
of args.  MAX is the maximum number or the symbol `many', for a lambda
or macro with `&rest' args."
  (let* ((arglist (help-function-arglist function))
         (optional-arglist (memq '&optional arglist))
         (rest-arglist (memq '&rest arglist)))
    (cons (- (length arglist)
             (cond (optional-arglist (length optional-arglist))
                   (rest-arglist (length rest-arglist))
                   (t 0)))
          (cond (rest-arglist 'many)
                (optional-arglist (+ (length arglist)
                                     (length optional-arglist)
                                     -1))
                (t (length arglist))))))

(defun function-arity ( function )
  (if (subrp function)
    (subr-arity function)
    (lambda-arity function)))
1
1

In addition to function func-arity (which @Tommy mentioned), there is function subr-arity, for functions defined in C source code, not Lisp. C-h f subr-arity says:

subr-arity is a built-in function in ‘C source code’.

(subr-arity SUBR)

Return minimum and maximum number of args allowed for SUBR.

SUBR must be a built-in function. The returned value is a pair (MIN . MAX). MIN is the minimum number of args. MAX is the maximum number or the symbol many, for a function with &rest args, or unevalled for a special form.

0

Check the actual Emacs version, and act based on what you know to be correct for that version.

Just knowing how many arguments are expected is insufficient. Imagine that the function changes again in future to add a second argument which is different to the original second argument -- you don't want your code to get the two mixed up.

You can test (version< emacs-version VERSION-STRING) or just (< emacs-major-version INTEGER) if that's sufficient (which is fairly likely with API changes).

3
  • Ah! I thought there oughta be something better than (string-to-number emacs-version). I wonder why it's not a float in the first place..? Oct 3, 2020 at 11:40
  • Floats are imprecise in any case, but a version can be more than simply X.Y. The current stable release of Emacs is 27.1, but the development version was 27.0.50, and in general version strings may contain suffixes like alpha1, beta3, and rc2.
    – phils
    Oct 3, 2020 at 12:56
  • Actually, that's what I ended up doing. I'm not particularly happy with that, because sometimes, I tweak the code myself and add arguments, which means the version isn't a safe way to get the "signature" of a function, but then it is lisp and not a strongly typed language. Oct 4, 2020 at 14:09

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

Not the answer you're looking for? Browse other questions tagged or ask your own question.