缺少的函数没有Erlang编译时错误

缺少的函数没有Erlang编译时错误,erlang,Erlang,为什么在调用另一个不存在或具有错误算术的模块中的函数时没有编译时错误或警告 编译器在一个模块中拥有所有导出信息,使之成为可能。它只是还没有实现,还是有一个技术原因导致我看不到它?我不知道为什么它会丢失(可能是因为模块是完全独立的,一个模块的编译实际上并不依赖于另一个模块,但这只是猜测)。但是我相信你可以通过透析器静态分析发现类似的问题。看看 它是系统本身的一部分,因此请尝试将其包含在您的工作流中。这是由于热代码加载。每个模块可以在任何特定时间加载。因此,当您的模块A中有一个调用函数B:F的代码时

为什么在调用另一个不存在或具有错误算术的模块中的函数时没有编译时错误或警告


编译器在一个模块中拥有所有导出信息,使之成为可能。它只是还没有实现,还是有一个技术原因导致我看不到它?

我不知道为什么它会丢失(可能是因为模块是完全独立的,一个模块的编译实际上并不依赖于另一个模块,但这只是猜测)。但是我相信你可以通过透析器静态分析发现类似的问题。看看


它是系统本身的一部分,因此请尝试将其包含在您的工作流中。

这是由于热代码加载。每个模块可以在任何特定时间加载。因此,当您的模块
A
中有一个调用函数
B:F
的代码时,当您的模块
B
的源代码没有函数
B:F
时,您无法判断它在编译时是错误的。想象一下:您通过调用
B:F
编译模块
A
。您将模块
B
加载到内存中,而不使用函数
B:F
。然后加载模块
A
,该模块包含调用
B:F
,但不调用它。然后用
B:F
编译模块
B
的新版本。然后加载这个新模块,然后您可以调用
B:F
,一切都很正常。设想您的模块
A
使模块
B
处于运行状态并加载它。在任何特定时间,您都无法判断模块
A
包含对不存在的函数的调用
B:F

是错误的。在我看来,大多数(如果不是全部的话)编译器都不会在编译时验证函数是否存在。通常需要函数的原型声明:返回值的类型、所有参数的列表和类型。这在C/C++中通过在每个模块定义(而不是.C或.cpp)中包含一些_文件.h来实现

在Erlang中,这种类型验证是在程序运行时动态完成的,因此不需要包含这些定义。它甚至是完全无用的,因为Erlang允许在运行中升级应用程序,因此函数类型可能会更改,或者在应用程序生命周期内,函数可能会故意或错误地消失;这就是为什么Erlang设计器选择在运行时而不是在构建时进行此验证

您提到的错误通常发生在代码生成的链接阶段,当“编译器”试图收集所有单独的目标代码片段以构建可执行文件或库时,在此阶段链接器解决所有外部地址(对于共享变量、静态调用…)。这个阶段在Erlang中不存在,一个模块是完全自包含的;它不与应用程序的其余部分共享任何内容,也不共享变量或函数地址


当然,在更新一个正在运行的生产程序之前,必须使用一些工具并进行一些测试,但是我认为这些验证的重要性与算法本身的正确程度完全相同。

编译时如模块<代码> Alpha < /代码>,它调用了<代码> beta:某个函数(…),编译器不能假定运行时使用某个特定版本的
beta
。在编译
alpha
之后,您可能会编译一个较新版本的
beta
,这将导出正确的
某些函数。也许您将上传
alpha
,以便在不同的主机上使用,该主机具有所有其他模块


因此,编译器只编译远程调用,任何错误(不存在的模块或函数)都将在运行时解决,此时将加载某个版本的
beta

正如其他人所说。模块是单独编译的,绝对不能保证编译时存在的环境与运行时将退出的环境相同。这意味着在编译时检查模块或其中函数的存在性基本上是没有意义的。在运行时,该模块可能会被加载,也可能不会被加载,您调用的函数可能会被定义,也可能不会在模块中被定义,或者它可能会执行与您预期完全不同的操作

所有这些都归功于Erlang系统的动态特性。并没有真正的方法来定义运行时系统中的内容。热代码加载是其中的一部分,由于系统的动态特性,它可以正常工作。这意味着您可以在运行时重新定义系统,可以使用不同的界面加载现有模块的新版本,可以加载全新模块并删除现有模块

要使其起作用,所有关于模块或函数存在性的检查都必须在运行时完成

诸如透析器之类的工具可以帮助您完成这项工作,但它们确实假设您在运行时没有做任何“有趣”的事情,并且您检查的系统与您运行的系统相同。这当然很好,但非常静态。与厄兰的天性相反,厄兰的天性是在任何事情上都是动态的


不幸的是,在这种情况下,您不能既有蛋糕又有蛋糕。

您可以使用
xref
应用程序来检查已弃用、未定义和未使用的函数(以及更多)的使用情况

使用调试信息编译模块:

Eshell V6.2  (abort with ^G)
1> c(test, debug_info).
{ok,test}
使用外部参照:m/1检查模块:

2> xref:m(test).
[{deprecated,[]},
 {undefined,[{{test,start,0},{erlang,foo,0}}]},
 {unused,[]}]
您可能想在此处查看有关
xref
的更多信息:


我知道透析器,但还没有完全掌握它或它的输出。我必须检查它是否足够快,以便在保存文件时运行并提供反馈。关于使用
透析器进行此类错误检测,尽管我强烈建议这样做(因为透析器功能更强大