为什么 Erlang 元组模块有争议?

Why Erlang tuple module is controversial?

有人问了一个类似的问题Parameterised Modules in Erlang,是关于"what"的。我的问题是关于 "why"?

OTP Technical Board - Decisions affecting R16 包含董事会关于此问题的决定,但我不知道该决定背后的原因。

Stateful Module in Programming Erlang 2ndEdition by Joe Armstrong详细介绍了这个功能,但是看不出作者的态度

如果我们阅读官方文档Function Calls, we see this feature is deliberately skimmed. In fact, the official document strongly discourages using this feature, refer to efficiency function calls。如果是这样,为什么 Joe Armstrong 在他的书中提到了这样的功能?

我觉得这个功能很棒。正如上面书中提到的,我的客户端代码可能如下所示

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

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

我无法告诉你控制一切的大阴谋集团内部讨论了什么,但我可以告诉你一些我从未考虑过使用此功能的原因:

  1. 不合适。 Erlang 是函数式的,这是对 OOP 风格的结构的一种奇怪的介绍,这种结构有胳膊和腿之类的东西。我不喜欢我的代码与自身发生冲突。
  2. 它引入了句法复杂性和语义歧义,但没有赋予我新的超能力。

    • 复杂度:

      1. "Is attribute X of Foo equal to 10 or 20 right now?"
      2. "为什么我在这里写dict:is_key(Value, Thingy)然后在那边写Thingy:is_key(Value)
      3. "Do I really want to encounter code like dict:is_key(Key, Foo:get_value(Key2)) all the time?"
      4. 我已经有一大群流程设计来做到这一点,并将状态的复杂性从流程代码中转移到异步消息的世界中(在代码中,我可以在一个单一的时间中处理一个孤立的时间快照函数的调用)...
      5. 如果我真的需要这个,这不是进程字典的用途吗?
    • 歧义:

      1. "Is this a 'thing' I'm calling a method of, or a module function I'm calling?"
      2. "Wait, wasn't this supposed to be functional?"
      3. "Is it OK to put that in a closure and send it off somewhere else? What if 'somewhere else' is another node? Do I have to start caring about that suddenly?"
  3. 这引入了不透明状态(坏)而不是 ADT(好,我们已经有了)。

  4. 没有人使用它,所以为什么要浪费精力支持它,特别是考虑到它可能带来的极端情况。这是支持开销和工作,我宁愿看到我们都使用的功能。
  5. 这里的"gain"只是对Java主义舍不得的人的一种福利。 Foo:is_key(Key)dict:is_key(Key, Foo) 之间没有太大区别。除了我在第一次阅读时 确定 之外,即使在完全没有上下文的情况下,第二个版本中操作的数据对象绝对是一个字典。

Erlang 的符号分配(又名 "single assignment")很棒,为什么要破坏它?

还有其他问题:

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

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

  • 很难将函数中的错误与调用联系起来,因为 arity 不同。

还有更多。我认为我们在摆脱参数化模块时没有摆脱元组模块是一种耻辱。它们最初只是实现参数化模块的一种 hacky 方式。