Область видимости, как ее игнорируют. И как лечить. Локальные и глобальные шутки.
Сегодня был очень интересный разговор, суть которого свелась к вопросу: "Если есть несколько кодов lsp от разных авторов, то как быть с повторением имен функций?" Действительно, в LISP нет (как бы) понятия public и private, но есть локальные функции и параметры. Честно говоря, я уже не помню, разговор был или нет про это дело. Но если был, то ничего страшного - слегка повторимся.
Сначала немного теории. Кто ее знает, ближайшие 5-6 абзацев могут спокойно пропускать.
Как известно, в lisp-функцию можно передавать какое-то количество параметров (подробнее см. О параметрах вызова и "перегрузке" фунций). Но существуют еще и т.н. локальные переменные. Они упоминаются в объявлении функции после знака слеша:
1 2 3 | (defun ИмяФункции(ПараметрыФункции / ЛокальныеПеременныеФункции) ;;; <...> );_ end of defun |
Чем хороши локальные элементы? Ну, хотя бы тем, что они уничтожаются после выхода из функции. Рассмотрим элементарный пример:
1 2 3 4 5 | (defun test1 (/ x) (setq x "qwer") (princ (strcat "\n" x)) (princ) ) ;_ end of defun |
И тут же выполним:
1 2 3 4 5 6 7 8 | _$ (setq x "1234") "1234" _$ (test1) qwer _$ x "1234" _$ |
Переменная х на момент вызова test1 равна "1234", внутри функции test1 новой переменной с тем же именем присваивается значение "qwer", а после выхода новая переменная уничтожается.
Точно так же можно оперировать не только с переменными, но и с функциями, задавая их область видимости. Подобный подход, например, показывался в Код без ошибок - возможно ли?.
Теперь теория кончилась, начинается практика
Допустим, у нас есть два кода от разных авторов. Первый:
1 2 3 4 5 6 7 | (defun fun1 () (aa "fun1") ) ;_ end of defun (defun aa (name) (alert (strcat "aa from " name)) ) ;_ end of defun |
Второй:
1 2 3 4 5 6 7 | (defun fun2 () (aa "fun2" "test") ) ;_ end of defun (defun aa (name param1) (alert (strcat "aa from " name ". " param1)) ) ;_ end of defun |
Видно, что функция aa в разных кодах имеет разное количество параметров. Что делать, как быть, если надо использовать и первый код, и второй? Ведь последовательность загрузки lsp определит, какая функция aa будет использоваться!
Мораль сей басни очень проста: надо "загнать" все подобные шутки в локальные переменные. Для этого откроем, например, Notepad++ и загрузим туда lsp-файлы. Поскольку в Notepad++ прекрасно работает подсветка синтаксиса и "сворачивание" функций, "сворачиваем" функции до уровня объявлений:
Теперь осталась самая малость: сделать глобальное объявление своей функции, загнав все имеющиеся в ее локальные:
Останется только загрузить новый файл.
Аналогичным образом можно поступить со всеми имеющимися кодами. Да, работа нудная и тяжелая, но иногда необходимая.
P.S. В некоторых случаях может помочь клавиатурное сочетание в vlide Ctrl+Shift+C, но лично у меня оно почему-то работает не совсем корректно, так что я не могу его рекомендовать.