Почему 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 (Справочное руководство по инструментам)