在一个大约有6000行Erlang代码但没有类型-spec()
注释的项目中,我尝试了以下操作:
typer --annotate *.erl
我用带注释的文件替换了所有的*.erl
文件并运行
dialyzer --src -c *.erl
我期望得到很多警告(第一次运行dialyzer/type组合),但在做了它的事情之后,所有dialyzer报告的都是user_default中同时不存在的函数的2个旧调用。
没有其他默认警告触发。
是我用错了吗?还是像这样的结果很常见?
是自动注释与typer
和dialyzer
的组合不那么有用,还是我只是幸运,我的代码没有问题?
旁注:我不得不注释掉3或4个-spec()
,因为dialyzer
崩溃了。
我正在使用Dialyzer v2.2.0和TypEr v0.1.7.4从Erlang R13B04
作为在erlang-bugs列表中报告错误的副作用,我从dialyzer和type的发明者Kostis Sagonas那里得到了详细的回答。
对于我的侧面问题,我得到了以下伟大而详细的答案:
2011年5月1日星期日下午5:53,Kostis Sagonas写道:
Peer Stritzinger写道:
顺便说一句:在做——注释时没有得到任何警告是正常的吗在类型和透析器中,没有手动调整规格
是的。实际上,type只是透析器基本类型推断的前端(即没有警告识别组件)。
在我看来,如果你不打算手动"按摩"你得到的规格并为其中一些提供更多信息,那么这样做就没有什么意义了。看看你以前的计划。这两个<<:64,:_*8>>类型指的是同一个量,如果您像下面这样引入一个类型,可以更好地表达这一事实:
-type packet() :: <<_:64,_:_*8>>,
通道类似:
-type channel() :: atom() | pid() |{atom(),_}.
,那么规格说明已经看起来更好了。此外,透透器/类型没有关于你打算在函数
recv/3
的第二个参数中使用什么类型的乐趣的信息,但你这样做!从代码中可以清楚地看出,它接受#can_pkt{}
记录,那么为什么不为它的字段添加适当的类型并为它引入类型呢?-record(can_pkt, {id :: id(), data :: binary(), timestamp :: ts()}). -type can_pkt() :: #can_pkt{}.
那么规格可以看起来更好:
-spec recv(packet(), fun((can_pkt()) -> R), channel()) -> R. -spec decode(packet()) -> can_pkt().
,请注意,我使用了占位符类型变量
R
来表示函数recv/2
返回第二个参数所返回的类型。你可能知道这个类型是什么,所以你也应该为它引入一个类型,并使用它的适当名称。希望有帮助,
科斯
p。很遗憾你在erlang-bugs中发布了这篇文章,因为在我看来,上面包含的信息比实际的bug更有趣。
因为他引用了我在bug报告中包含的代码片段,所以我在这里包含了它。以下代码片段由typer --annotate
自动注释:
-record(can_pkt, {id, data, timestamp}).
-spec recv(<<_:64,_:_*8>>,fun((_) ->
any()),atom() | pid() | {atom(),_}) -> any().
recv(Packet, Recv_fun, Chan) ->
P = decode(Packet),
#can_pkt{id=Can_id, data=Can_data}=P,
Recv_fun(P).
-spec decode(<<_:64,_:_*8>>) ->
#can_pkt{id::<<_:11>>,data::binary(),timestamp::char()}.
decode(<<_:12, Len:4, Timestamp:16,
0:3, Id:11/bitstring, 0:18,
Data:Len/binary, _/binary>>) ->
#can_pkt{id=Id, data=Data, timestamp=Timestamp}.