【问题标题】:How does Smalltalk deal with monkeypatching?Smalltalk 如何处理猴子补丁?
【发布时间】:2009-05-18 21:21:45
【问题描述】:

我是一名 Ruby 程序员。对我来说,monkeypatching 是在运行时更改外部项目中的类或模块方法。我感兴趣的是,您有什么机制可以保护您免受某些对该功能的滥用。接下来是我遇到的一些场景,monkeypatching 让我很痛苦。

虽然我根本不了解 Smalltalk,但这种语言早在 Ruby 之前就已经存在了。我做了一些研究,看看 Smalltalk 是否以及如何解决其中的一些问题,但在 Google 上没有找到太多。所以我在这里,询问 Smalltalkers 是否可以分享他们的智慧。

场景 A:错误修复冲突

项目 A 和 B 依赖于项目 C。项目 C 有一个错误。项目 A 和 B 版本包含对项目 C 的修复。

如果你的代码使用项目 A 和 B,你怎么知道补丁不会冲突?

场景 B:过时的错误修复

项目 C 发布其项目的固定次要版本。

如果您加载项目 A,是否仍会应用补丁,但可能会损坏?我很想知道是否存在某种机制,例如,如果代码已修复,则不加载补丁。

场景 C:冲突扩展

项目 A 和 B 使用项目 C 的类 Foo。两者都向 Foo 添加了一个实用方法,例如 #toDate。 A 的 toDate 版本返回日期字符串,B 的版本返回 Date 对象。

如果您加载两个项目(使用 C dep),是否有一种机制可以警告/防止冲突?或者您是否必须等到运行时由于方法中的错误期望而引发错误?

关于问题更新

阅读答案后,我意识到我的问题过于笼统和模糊。所以这里是它的重写版本。

【问题讨论】:

  • monkeypatch 真的是个问题吗?
  • 您对猴子补丁的批评似乎离题太远了。与初始类设计相比,monkeypatching 中没有任何内在的东西会导致抽象泄漏。它本身也不比其他代码更“粗糙”。将一个对象拆分为不同的文件是正确的,尽管有些人认为拥有可管理的模块是一件好事——事实上,在 Objective-C 中对相关功能进行分组被认为是一种很好的做法。也许您的问题更多是与编码器有关,而不是语言功能。
  • 在任何情况下,将事物拆分为单独文件的整个概念都是错误的。 smalltalk 不会那样做。
  • @CookieOfFortune & @Chuck:我的问题应该更具体,谢谢指出。

标签: ruby smalltalk monkeypatching


【解决方案1】:

在 Smalltalk 中,我们传统上将其称为覆盖。根据您在 Smalltalk 中使用的版本控制工具,您可以选择;

  • 创建最初拥有相关类/方法的包的新版本
  • 创建一个新包,该包将拥有相关类/方法的覆盖

在 VisualWorks 和 ObjectStudio(我最熟悉的 Smalltalk)中,使用的是后一种方法。在使用 Envy 的 VA Smalltalk 中,采用了前一种方法。我相信 Squeak 会采用后一种方法使用蒙蒂塞洛,但我并不完全确定。

在大多数 Smalltalk 实现中,很容易看到被覆盖代码的原始版本和当前安装的覆盖。

在客户端应用程序中,只有当您从供应商(或 Squeak 团队等)更新到新版本的 Smalltalk 时,覆盖才会真正影响您。对于服务器应用程序,可能有多个应用程序驻留在服务器中,您需要更加谨慎地决定要做什么。

覆盖(或称为猴子补丁)是一个强大的工具,但您需要注意如何使用它们 - 如果您确实使用它们,您应该重新检查是否仍然需要它们定期。在我的开源新闻聚合器BottomFeeder 中,我删除了很多我最初设置的覆盖。

【讨论】:

    【解决方案2】:

    它说“是的!去吧!”

    整个概念很可能首先出现在 Smalltalk 中。

    在类浏览器中进入根类,可以将所有方法添加到你喜欢的图片中。

    不过,请记住,Smalltalk 对世界的描述与其他常用语言截然不同(Smalltalk 等唯一常见的语言是 APL。)您有一个包含整个集合的图像代码和运行时包。当您更改图像时,图像中的每一位代码都会受到影响。其他图像不变。您可以使用更改集来重新加载您最喜欢的 hack,但它们基本上是将代码导入图像中。

    【讨论】:

      【解决方案3】:

      Smalltalkers 不使用术语“猴子修补”,但我觉得“方法覆盖”是最接近的术语。也就是用包B中同一个类的方法覆盖A包中一个类的方法。所以当你加载包B时,A中的原始方法被覆盖了。

      方法覆盖有其优点,但如果不小心使用,则缺点更多,因此通常我们倾向于避免使用它们。它还取决于 Smalltalk 方言 - 例如,在 VisualWorks 中,工具非常支持覆盖,而在 Squeak 中则不然。

      【讨论】:

      • +1 用于识别每个(亚)文化中术语使用的重要性,-1 用于混淆方法覆盖(完全不同的事情)
      • 在阅读了关于猴子补丁的维基百科文章之后,显然不是完全不同的事情。好吧,似乎在 Smalltalk 中我们只是通过更改实时图像中的某些方法来进行猴子修补?无论如何,我们一直都在这样做。
      • 用新话来说真的是一样的:)
      【解决方案4】:

      如果您正在寻找最先进的解决方案,请查看 Changeboxes。 Changeboxes的研究原型基于Squeak Smalltalk。

      http://scg.unibe.ch/research/changeboxes

      【讨论】:

        【解决方案5】:

        回答我自己,这是我目前的观点:

        场景 A 和 B

        由于所有代码都是开放的,最好的做法是直接修复损坏的项目。像 git 这样的工具已经管理代码合并,所以我们不需要依赖运行时合并,这并不总是有效。

        根据上游合并您的修复程序的意愿和发布新版本的速度,您可能会设想生成一个猴子补丁。在这种情况下,最好的机制是:

        monkeypatch(ClassName, :method, &newcode) of the broken project
        is applied if project.version in [a set of releases where the bug exist]
        if the project version is unknown to the monkeypatch,
          raise an error to tell the developer to fix the monkeypatch (check if bug exist).
        if a monkeypatch for that project, classname and method already exist, yell
        

        这是我的想法。如果错误修复需要的不仅仅是方法更改,则可能会出现问题。

        场景 C:待办事项

        【讨论】:

        • 对于场景 C,避免冲突的最好方法是使用选择器命名空间,所以如果你有包 Foo 和包 Bar,都想扩展某些类的行为,比如添加 #toDate: 方法,你扩展它 2 次:使用 fooToDate: name 扩展包 Foo 和包 Bar, - barToDate: 。问题消失了:)
        猜你喜欢
        • 2012-01-30
        • 1970-01-01
        • 2011-10-06
        • 2020-05-24
        • 2016-09-01
        • 2012-09-16
        • 2012-12-18
        • 2020-01-09
        • 1970-01-01
        相关资源
        最近更新 更多