为什么Erlang元组模块备受争议?

7

一个类似的问题被问到了Erlang中的参数模块,那个问题是关于“什么”的。我的问题是关于“为什么”的。

OTP技术委员会 - 影响R16的决策 包含了有关此问题的委员会决定,但我不知道这个决定背后的原因。

Joe Armstrong在《Programming Erlang第二版》中详细介绍了带状态的模块,但我没有看到作者的态度。

如果我们阅读官方文档函数调用,我们可以看到这个特性被故意略过了。事实上,官方文件强烈反对使用这个特性,参见效率函数调用。如果是这样,为什么Joe Armstrong在他的书中提到了这个特性呢?

我认为这个特性很棒。正如上面的书所提到的,我的客户端代码可以像下面这样

Obj:find(Key),
Obj:is_key(Key),

那么,我们并不关心 Obj 是由 dict:new() 还是 gb_tree:new() 创建的,但遗憾的是,dictgb_tree 没有共享一致的 接口,例如,我们有 gb_tree:lookup 而不是 gb_tree:find


我发现这个功能在实现一些边界模块时非常有用。在生产代码中,它们只是普通的模块,但对于测试,有一个虚假的边界,通常具有状态,因此我使用元组模块。就像这个问题中所示:http://stackoverflow.com/questions/32860342/define-a-constant-module-in-elixir/32861188#32861188 - Peter Saxton
2个回答

7
我不能告诉你控制一切的伟大阴谋小组的讨论内容,但我可以告诉你为什么我从未考虑使用这个功能:
1. 它不匹配。Erlang 是一种函数式语言,而这里介绍了类似于具有手臂和腿的面向对象结构体的奇怪概念。我不喜欢我的代码之间发生冲突。
2. 它引入了语法复杂性和语义模糊性,但却没有赋予我新的超能力。 - 复杂性: - “Foo 的属性 X 现在是 10 还是 20?” - “我为什么要在这里写 dict:is_key(Value, Thingy) ,然后在那里写 Thingy:is_key(Value)?" - "我真的想一直遇到这样的代码吗 dict:is_key(Key, Foo:get_value(Key2))?" - 我已经有了一支专门处理这种情况并将状态复杂性从进程代码中移出到异步消息世界的进程军队(在函数的单次调用中我可以处理隔离时间的快照)... - 如果我真的需要这个功能,这不就是进程字典的作用吗? - 模糊性: - “我正在调用一个方法的‘东西’,还是调用一个模块函数?” - “等等,这不应该是函数式的吗?” - “将其放在闭包中并将其发送到其他地方是否可以?如果‘其他地方’是另一个节点怎么办?我突然要开始关心这个了吗?”
3. 它引入了不透明状态(不好)而不是抽象数据类型(好的,我们已经有了)。
4. 没有人使用它,为什么浪费精力支持它,特别是考虑到它可能带来的棘手问题。这是支持开销和努力,我宁愿看到它们投入到我们所有人都使用的功能中去。
5. 这里的“增益”只被视为无法割舍 Java-isms 的人的利益。Foo:is_key(Key) 和 dict:is_key(Key, Foo) 之间几乎没有什么区别。除了第二个版本中的数据对象在完全没有上下文的情况下,在第一次阅读时就能清楚地确定为字典以外。
Erlang 的符号赋值(也称为“单赋值”)很棒,为什么要破坏它呢?

该功能不会破坏“单一赋值”,Joe建议使用类似D2 = D1:insert(K,V)的方式,这与传统的面向对象语言非常不同,D1保持不变。该功能使我们能够编写更通用的库,例如A=[dict:new(), gb_tree:new()],稍后,我们可以将A传递给库函数,例如has_car(A) -> lists:filter(fun (D) -> D:is_key(car) end, A)。无论如何,我同意您的观点,例如“它不适合”,“歧义”,“不透明状态”等。 - wcy
@wcy,我对单赋值的理解可能是错误的。我记得看到过一些代码(也许是一个未实现的早期概念?),其中类似于 ok = D:set_foo(10), 10 = D:get_foo(), ok = D:set_foo(20), 20 = D:get_foo() 的东西在 OOP 语言中的工作方式就像请求整个麻烦球一样。无论如何,使用单赋值,我认为这种类似于 OOP 的语法比可变性更加毫无意义。只是一个不好的匹配,将我们从另一个范例中熟知的语义带入这个领域,但改变了任意细节。 - zxq9

4

还存在其他问题:

  • 当我写Foo:bar(42)时,其中Foo可能是模块名称,也可能是元组模块,但我看不出区别。这意味着我可能会调用bar/1bar/2

  • 我可以以不同的方式调用相同的函数。

  • 很难将错误与函数调用关联起来,因为元数不同。

还有更多的问题。我认为当我们摆脱参数化模块时,应该也摆脱元组模块。它们最初只是实现参数化模块的hacky方法。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接