我有一个没有-spec
或-type
在代码中的项目,目前透析器可以找到一些警告,其中大部分是在机器生成的代码中.
将类型规格添加到代码中会使透析器发现更多错误吗?
关于主题,是否有任何工具来检查规格是否被违反?
添加typespecs将显着提高Dialyzer 的准确性.
因为Erlang是一种动态语言,所以Dialyzer必须默认对类型进行相当广泛的解释,除非你给它一些提示来缩小它的"成功"类型.可以把它想象成给Dialyzer一个过滤器,通过它可以将一组可能的成功转换为应该工作的显式类型的子集.
这与Haskell不同,默认假设是失败,所有代码必须写成成功输入才能编译 - Dialyzer必须默认为成功,除非它确定类型将会失败.
Typespecs是其中的主要部分,但Dialyzer也会检查守卫,所以功能就像
increment(A) -> A + 1.
是不一样的
increment(A) when A > 100 -> A + 1.
虽然两者都可以打字
-spec increment(integer()) -> integer().
大多数时候,你只在乎整数值是integer()
,pos_integer()
,neg_integer()
,或non_neg_integer()
,但有时你只需要在一侧限定的任意范围-和式语言没有办法目前来表示这个(虽然我个人希望看到一个100..infinity
按预期工作宣言).
无界范围when A > 100
需要一个守卫,但有限的范围when A > 100 and A < 201
可以单独在typespec中表示:
-spec increment(101..200) -> pos_integer(). increment(A) -> %stuff.
除了调用之外,防护是快速的length/1
(你可能永远不需要在防护中),因此在你真正了解并且可以证明你有来自防护的性能问题之前不要担心性能开销.使用警卫和类型来约束Dialyzer是非常有用的.它也非常适合作为您自己的文档,特别是如果您使用edoc,因为typespec将在那里显示,使API不那么神秘,并且易于玩具一目了然.
有一些关于在现有代码库中使用Dialyzer的有趣文献.这里有详细记录的体验:Erlang程序的逐步打字:牧马人体验.(不幸的是,我从之前学到的其他一些链接已经消失或移动了.(!.!)仔细阅读牧马人论文,浏览用户指南和手册页,玩Dialyzer,以及之前的一些经验像Haskell这样的类型系统不仅可以帮助您从Dialyzer获得大量的里程数.)
[侧面说明,我之前已经与一些人谈过指定"纯"函数,这些函数可以通过符号或使用不同的定义语法(也许是Prolog :-
而不是Erlang的->
......)来保证强类型.虽然那会很酷,但现在甚至很有可能将副作用集中在程序的一小部分并将所有结果传回一个元组中{Results, SideEffectsTODO}
,这根本不是迫切的需要而且Erlang的工作非常有用一如既往.但是Dialyzer确实非常有助于向你展示你已经失去了自己的踪迹!]