EDIT : Uma maneira melhor de fazer isso no Emacs recente é definindo uma macro do compilador para verificar o número de argumentos. Minha resposta original usando uma macro normal é preservada abaixo, mas uma macro de compilador é superior porque não impede a passagem da função para funcall
ou apply
em tempo de execução.
Nas versões recentes do Emacs, você pode fazer isso definindo uma macro de compilador para sua função que verifica o número de argumentos e produz um aviso (ou até mesmo um erro) se não corresponder. A única sutileza é que a macro do compilador deve retornar o formulário de chamada de função original inalterado para avaliação ou compilação. Isso é feito usando um &whole
argumento e retornando seu valor. Isso poderia ser realizado assim:
(require 'cl-lib)
(defun my-caller (&rest args)
(while args
(message "%S %S" (pop args) (pop args))))
(define-compiler-macro my-caller (&whole form &rest args)
(when (not (cl-evenp (length args)))
(byte-compile-warn "`my-caller' requires an even number of arguments"))
form)
(my-caller 1 2 3 4)
(my-caller 1 2)
(funcall #'my-caller 1 2 3 4) ; ok
(apply #'my-caller '(1 2)) ; also ok
(my-caller 1) ; produces a warning
(funcall #'my-caller 1 2 3) ; no warning!
(apply #'my-caller '(1 2 3)) ; also no warning
Note-se que funcall
e apply
agora pode ser usado, mas eles Ignorar verificação argumento pela macro compilador. Apesar do seu nome, macros compilador também parecem ser expandida no curso de 'interpretada' avaliação via C-xC-e, M-xeval-buffer, assim que você vai obter erros na avaliação, bem como sobre a compilação neste exemplo.
A resposta original segue:
Aqui está como você pode implementar a sugestão de Jordon de "usar uma macro que fornecerá avisos no momento da expansão". Acontece que é muito fácil:
(require 'cl-lib)
(defmacro my-caller (&rest args)
(if (cl-evenp (length args))
`(my-caller--function ,@args)
(error "Function `my-caller' requires an even number of arguments")))
(defun my-caller--function (&rest args)
;; function body goes here
args)
(my-caller 1 2 3 4)
(my-caller 1 2 3)
A tentativa de compilar o acima em um arquivo falhará (nenhum .elc
arquivo é produzido), com uma boa mensagem de erro clicável no log de compilação, informando:
test.el:14:1:Error: `my-caller' requires an even number of arguments
Você também pode substituir (error …)
por (byte-compile-warn …)
para produzir um aviso em vez de um erro, permitindo que a compilação continue. (Obrigado a Jordon por apontar isso nos comentários).
Como as macros são expandidas no momento da compilação, não há penalidade no tempo de execução associada a essa verificação. Obviamente, você não pode impedir que outras pessoas liguem my-caller--function
diretamente, mas pelo menos pode anunciar como uma função "privada" usando a convenção de hífen duplo.
Uma desvantagem notável de usar uma macro para esse fim é que ela my-caller
não é mais uma função de primeira classe: você não pode passá-la para funcall
ou apply
em tempo de execução (ou pelo menos ela não fará o que você espera). Nesse aspecto, essa solução não é tão boa quanto poder simplesmente declarar um aviso do compilador para uma função real. Obviamente, o uso apply
tornaria impossível verificar o número de argumentos que estão sendo passados para a função em tempo de compilação, portanto, talvez essa seja uma troca aceitável.