Общее использование советов — это именованные функции и макросы.
Вы могли бы просто использовать add-function, как в следующем примере:
(add-function :around (symbol-function 'fun) #'his-tracing-function)
Но вместо этого вы должны использовать advice-add и advice-remove. Этот отдельный набор функций для манипулирования частями советов, примененных к именованным функциям, предлагает следующие дополнительные возможности по сравнению с add-function: они знают, как работать с макросами и автозагруженными функциями, они позволяют describe-function сохранять исходную строку документации, а также документировать добавленный совет, и они позволяют добавлять и удалять советы еще до того, как функция будет определена.
advice-add может быть полезен для изменения поведения существующих вызовов существующей функции без необходимости переопределять всю функцию.
Однако это может быть источником ошибок, поскольку существующие вызывающие могут предполагать старое поведение и работать некорректно, когда поведение изменяется советом. Совет также может вызвать путаницу при отладке, если человек, выполняющий отладку, не заметит или не вспомнит, что функция была изменена советом.
Обратите внимание, что проблемы вызваны не самим советом, а самим фактом изменения именованной функции. Еще более проблематично изменять именованную функцию с помощью низкоуровневых примитивов, таких как fset, defalias или cl-letf. С этой точки зрения, совет — это лучший способ изменить именованную функцию, потому что он отслеживает изменения, поэтому их можно перечислить и отменить.
Изменение именованной функции следует оставлять для случаев, когда вы не можете изменить поведение Emacs каким-либо другим способом. Если возможно сделать то же самое с помощью хука, это предпочтительнее (см. Хуки). Если вы просто хотите изменить то, что делает определенная клавиша, возможно, лучше написать новую команду и переназначить привязки клавиш старой команды на новую (см. Переназначение команд).
Если вы пишете код для выпуска, чтобы другие могли его использовать, старайтесь избегать включения советов. Если функция, которую вы хотите консультировать, не имеет хука для выполнения этой задачи, пожалуйста, поговорите с разработчиками Emacs о добавлении подходящего хука. В частности, собственные исходные файлы Emacs не должны применять советы к функциям в Emacs. (В настоящее время есть несколько исключений из этого правила, но мы стремимся их исправить.) В целом, чище создать новый хук в foo и заставить bar использовать этот хук, чем заставлять bar применять советы в foo.
Специальные формы (см. Специальные формы) не могут быть проконсультированы, однако макросы могут быть проконсультированы, в той же мере, что и функции. Конечно, это не повлияет на код, который уже был расширен макросом, поэтому вам необходимо убедиться, что совет установлен до того, как макрос будет расширен.
Возможно консультировать примитив (см. Что такое функция?), но обычно не следует этого делать по двум причинам. Во-первых, некоторые примитивы используются механизмом советов, и консультирование их может вызвать бесконечную рекурсию. Во-вторых, многие примитивы вызываются напрямую из C, и такие вызовы игнорируют советы; следовательно, вы оказываетесь в запутанной ситуации, когда некоторые вызовы (происходящие из кода Lisp) подчиняются совету, а другие вызовы (из кода C) — нет.
Этот макрос определяет часть совета и добавляет его к функции с именем
symbol. Если name не равен nil, совет имеет имя
symbol@name и устанавливается с именем name; в противном случае совет анонимный. См. advice-add для объяснения других аргументов.
Добавить совет function к именованной функции symbol.
where и props имеют то же значение, что и для add-function
(см. Примитивы для манипулирования советами).
Удалить совет function из именованной функции symbol.
function также может быть name части совета. При интерактивном вызове запрашивается как консультируемая function, так и совет для удаления.
Возвращает не-nil, если совет function уже находится в именованной
функции symbol. function также может быть name части совета.
Вызывает function для каждой части совета, добавленной к именованной функции symbol. function вызывается с двумя аргументами: функцией совета и ее свойствами.