Estoy escribiendo una función que, en principio, toma una cantidad arbitraria de argumentos. En la práctica, sin embargo, solo se debe pasar un número par de argumentos, y de lo contrario producirá resultados indeseables.
Aquí hay un ejemplo ficticio para el contexto:
(defun my-caller (&rest args)
(while args
(call-other-function (pop args) (pop args))))
Cuando un archivo elisp se compila en bytes, el compilador de bytes emite una advertencia cuando ve que se invoca una función con el número incorrecto de argumentos. Obviamente, eso nunca va a suceder my-caller
, ya que está definido para tomar cualquier número.
Aún así, tal vez haya una propiedad de símbolo que pueda establecer, o un (declare)
formulario que pueda agregar a su definición. Algo para notificar al usuario que esta función solo debe recibir un número par de argumentos.
- ¿Hay alguna manera de informar al compilador de bytes de esta restricción?
- Si no, ¿es posible con una macro, en lugar de una función?
fuente
Respuestas:
EDITAR : Una mejor manera de hacer esto en Emacs reciente es definiendo una macro compiladora para verificar el número de argumentos. Mi respuesta original utilizando una macro normal se conserva a continuación, pero un compilador-macro es superior porque no impide pasar a la función
funcall
oapply
en tiempo de ejecución.En versiones recientes de Emacs, puede hacer esto definiendo una macro compiladora para su función que verifica el número de argumentos y produce una advertencia (o incluso un error) si no coincide. La única sutileza es que la macro compiladora debe devolver el formulario de llamada de función original sin cambios para evaluación o compilación. Esto se hace usando un
&whole
argumento y devolviendo su valor. Esto podría lograrse así:Tenga en cuenta que
funcall
yapply
ahora se puede usar, pero omiten la comprobación de argumentos por parte de la macro compiladora. A pesar de su nombre, las macros del compilador también parecen ser ampliado en el curso de 'interpretado' evaluación a través de C-xC-e, M-xeval-buffer, por lo que obtendrá errores en la evaluación, así como en la elaboración de este ejemplo.La respuesta original sigue:
Así es como podría implementar la sugerencia de Jordon de "usar una macro que proporcionará advertencias en el momento de la expansión". Resulta muy fácil:
Intentar compilar lo anterior en un archivo fallará (no
.elc
se produce ningún archivo), con un bonito mensaje de error en el que se puede hacer clic en el registro de compilación, que indica:También puede reemplazar
(error …)
con(byte-compile-warn …)
para generar una advertencia en lugar de un error, permitiendo que continúe la compilación. (Gracias a Jordon por señalar esto en los comentarios).Como las macros se expanden en el momento de la compilación, no hay penalización en tiempo de ejecución asociada con esta verificación. Por supuesto, no puede evitar que otras personas llamen
my-caller--function
directamente, pero al menos puede anunciarlo como una función "privada" utilizando la convención de doble guión.Una desventaja notable de usar una macro para este propósito es que
my-caller
ya no es una función de primera clase: no puede pasarlafuncall
oapply
en tiempo de ejecución (o al menos no hará lo que espera). En ese sentido, esta solución no es tan buena como poder simplemente declarar una advertencia del compilador para una función real. Por supuesto, el usoapply
haría imposible verificar el número de argumentos que se pasan a la función en tiempo de compilación de todos modos, por lo que tal vez sea una compensación aceptable.fuente
byte-compile-warn
apply
ofuncall
la envoltura macro. Lo probaré y editaré mi respuesta si funciona.Sí, puede usar
byte-defop-compiler
para especificar realmente una función que compila su función,byte-defop-compiler
tiene algunas sutilezas incorporadas para ayudarlo a especificar que sus funciones deben generar advertencias basadas en tener una serie de argumentos.Documentación
Agregue un formulario de compilación para FUNCTION. Si la función es un símbolo, entonces la variable "byte-SYMBOL" debe nombrar el código de operación que se utilizará. Si function es una lista, el primer elemento es la función y el segundo elemento es el bytecode-symbol. El segundo elemento puede ser nulo, lo que significa que no hay código de operación. COMPILE-HANDLER es la función que se utiliza para compilar este byte-op, o pueden ser las abreviaturas 0, 1, 2, 3, 0-1 o 1-2. Si es nulo, el controlador es "byte-compile-SYMBOL".
Uso
En su caso específico, podría usar una de las abreviaturas para definir que su función debería recibir dos argumentos.
Ahora su función dará advertencias cuando se compila con cualquier cosa menos 2 argumentos.
Si desea dar advertencias más específicas y escribir sus propias funciones de compilación. Mire
byte-compile-one-arg
y otras funciones similares en bytecomp.el como referencia.Tenga en cuenta que no solo está especificando alguna función para manejar la validación, sino que también está compilando. Nuevamente, compilar funciones en bytecomp.el le proporcionará una buena referencia.
Rutas más seguras
Esto no es algo que haya visto documentado o discutido en línea, pero en general diría que esta es una ruta desaconsejada. La ruta correcta (IMO) sería escribir sus defuns con firmas descriptivas o usar una macro que proporcionará advertencias en el momento de la expansión, verificando la longitud de sus argumentos y usando
byte-compile-warn
oerror
para mostrar errores. También puede beneficiarle hacer uso de laeval-when-compile
verificación de errores.También necesitará que su función se defina antes de que alguna vez se use, y la llamada a
byte-defop-compiler
tendrá que ser antes de que el compilador llegue a las llamadas reales de su función.Una vez más, parece no estar realmente documentado o aconsejado por lo que he visto (podría estar equivocado), pero imagino que el patrón a seguir aquí sería especificar algún tipo de archivo de encabezado para su paquete que esté lleno de un montón de defuns vacíos. y llama a
byte-defop-compiler
. Básicamente, este sería un paquete que se requiere antes de que se pueda compilar su paquete real.Opinión: Basado en lo que sé, que no es mucho, porque acabo de enterarme de todo esto, te aconsejaría que nunca hagas nada de esto. nunca
fuente