Почему erlang: foo() компилируется?
Почему компилятор Erlang не обнаруживает функции undefined во время компиляции.
Если я пишу test.erl:
-module(test).
-export([start/0]).
start() ->
erlang:foo().
Он компилируется отлично.
Eshell V5.6.5 (abort with ^G)
1> c(test).
{ok,test}
2>
Но выходит из строя.
2> test:start().
** exception error: undefined function erlang:foo/0
Почему компилятор не выдает ошибку или предупреждение об этом во время компиляции? Он должен знать об экспортируемых функциях, не так ли?
Ответы
Ответ 1
Эрланг - динамический язык. Однако хорошей практикой является проверка типа и статический анализ после компиляции.
Инструмент Dialyzer используется для проверки такого рода условий ошибки.
Причина, по которой компилятор не знает об этом во время компиляции, состоит в том, что функции можно искать и динамически загружать из пути кода во время выполнения (а также из удаленного node). Dialyzer проверит код на пути к коду во время его запуска.
Возможность загрузки кода с удаленного устройства node означает, что базовые "системы" могут быть установлены на устройстве, и устройство может затем загрузиться из сети.
Вы также должны помнить еще одну характеристику Erlang, что вы можете генерировать вызовы функций на лету с помощью таких конструкций, как:
erlang:apply(ModuleName, FunctionName, ArgList)
поэтому в этом случае просто невозможно узнать, существует ли функция во время компиляции или нет.
И хотя модуль и функция могут существовать сейчас во время компиляции, вы можете отключить модули горячей замены и выгрузить код, поэтому он может отсутствовать во время выполнения.
Ответ 2
Я думаю, что это вопрос реализации, поскольку разработчики Erlang решили использовать компоновку времени выполнения, а не компоновку времени сборки. Часть причины может иметь что-то для управления версиями и/или динамического кода.
Ответ 3
Вы можете использовать приложение xref
для проверки использования устаревших, undefined и неиспользуемых функций (и более!).
Скомпилируйте модуль с помощью debug_info
:
Eshell V6.2 (abort with ^G)
1> c(test, debug_info).
{ok,test}
Проверьте модуль с помощью xref:m/1
:
2> xref:m(test).
[{deprecated,[]},
{undefined,[{{test,start,0},{erlang,foo,0}}]},
{unused,[]}]
Вы можете узнать больше о xref
здесь:
Erlang - Xref - Инструмент Cross Reference (Руководство пользователя инструментов)
Erlang - xref (Справочное руководство по инструментам)