Smalltalk 如何重写另一个包中类中的现有选择器

Smalltalk 如何重写另一个包中类中的现有选择器,smalltalk,pharo,Smalltalk,Pharo,我正在使用Pharo5.0。在一些情况下,我在现有的Pharo类(例如DBXTalk/Garage或Regex-Core)中发现了一个限制或可能的bug。我希望能够修改我自己项目之外的类中存在的选择器或选择器集,并将其作为我的包的一部分 我发现了一些关于如何在外部类中创建新选择器并将其移动到我的包中的说明(例如,如本文所示)。那很酷。但在某些情况下,我实际上希望修改外部类中的现有选择器,并在使用该选择器时使该选择器的副本覆盖外部类中的选择器。我不希望修改现有的第三方或Pharo预提供的软件包 在

我正在使用Pharo5.0。在一些情况下,我在现有的Pharo类(例如DBXTalk/Garage或Regex-Core)中发现了一个限制或可能的bug。我希望能够修改我自己项目之外的类中存在的选择器或选择器集,并将其作为我的包的一部分

我发现了一些关于如何在外部类中创建新选择器并将其移动到我的包中的说明(例如,如本文所示)。那很酷。但在某些情况下,我实际上希望修改外部类中的现有选择器,并在使用该选择器时使该选择器的副本覆盖外部类中的选择器。我不希望修改现有的第三方或Pharo预提供的软件包

在GNU Smalltalk中,我可以这样做,就像做类扩展一样。例如:

Kernel.MatchingRegexResults extend [
    at: anIndex [
        "My updated version of the 'official' Kernel.MatchingRegexResults#at: selector"
        "This is part of my package so overrides the 'official' version"
        ...
    ]

    foo [
        "My new foo selector"
    ]
]

如何在Pharo 5.0中实现这一点?我做了很多搜索,但找不到一个方法。单词“extend”或“override”不会出现在Pharo的示例中,也不会深入到Pharo书籍中。

GNU Smalltalk语法中的代码

Kernel.MatchingRegexResults extend [
    at: anIndex [
        "method body"
    ]
    foo [
        "My new foo selector"
    ]
]
看起来像这样

!MatchingRegexResults methodsFor: 'protocol'!
at: anIndex 
    "method body"
!
foo
    "My new foo selector"
! !
在Pharo变更集中,可以从文件浏览器归档

但请注意,在GNU Smalltalk和Pharo Smalltalk这两种情况下,您实际上是在替换该类中方法的原始版本

在GNU Smalltalk中,您可能不习惯保存图像,因此您可能认为extend语法不会修改原始类中的原始方法

实际上正是这样

使用GNU Smalltalk,您通常在每次运行gst时都从相同的未修改的旧映像开始。
这是因为GNU Smalltalk中图像的默认位置不能写入普通用户。所以gst每次都读取相同的只读映像,在内存中使用类定义和扩展对其进行修改,修改后的映像仅在程序运行时暂时存在,并在程序退出时丢弃

请注意,除了Milan Vavra编写的内容外,名为
*YourPackage-(something)
的协议中的每个方法都将属于包
YourPackage
,而不管该类属于哪个包。至少在Squeak中,有一种惯例,就是在
*yourpack override
协议中放置这样被覆盖的方法。法罗可能有类似的命名惯例。Move to package特性将方法移动到这样一个“星形”协议

但是,不鼓励使用此类重写,因为不能让两个包同时为同一方法提供实现。Monticello将尝试保留原始方法和重写方法(请参见
PackageInfo>>isOverrideCategory:
)的发件人),但仍然可能会有重写方法被其原始包的更新所重写,或者您将错过对原始方法的更新,可能会破坏某些功能


“正确的方法”是重构原始包中的原始方法,使其行为更易于自定义。

您是否尝试过迁移到包中。。。指挥部?可以从选择器列表的右键菜单中找到它。@LeandroCaniglia是的,我找到了。事实上,我在问题中提到了这一点。如果我想为现有的外部类创建一个新的选择器,并将该选择器移动到我的包中,那么这个移动非常有效。但它不适用于修改/覆盖现有选择器,因为它会将该选择器的实现移动到我的包中,并将其从外部包中删除。我不想从外部包中删除重写的选择器,但只想重写它。重写意味着重写。。。您将重新编写该方法,它将被移动到您的包中,但它将针对整个系统进行更改。Pharo没有模块系统,所以在同一个类中不能有同名的不同方法……我想从变更管理的角度来看,最好的办法可能是将修改后的选择器移动到我的包中,正如@LeandroCaniglia在他的评论中所说,即使这意味着修改现有包以移动它。至少这样很容易跟踪。如果我想共享此软件包,而其他人尝试使用它,那么我的软件包中修改的软件包将取代他们标准软件包中的软件包?或者这仅仅取决于上次在他们的环境中更新了哪个包?一个类中只能有一个方法版本。最近加载的方法版本将成为当前版本。星号协议仅用于将扩展方法分组到系统浏览器和Monticello浏览器的不同包中。不管包是什么,该方法都是同一类的一部分。对,但是如果它在多个包中定义,那么哪一个“获胜”?是否基于包装装载的顺序?当我在包Y中重新定义选择器定义的包X时,我知道Y版本将替换它。但是,如果我随后加载了更新版本的程序包X,那么如果选择器被更新版本替换,Y版本会被替换吗?或者它只是被跳过,而我的Y包版本仍然存在?如果您在更改集中归档,那么其中定义的所有方法都将替换映像中的方法。如果您使用Monticello.mcz文件,您可以单击“更改”来查看加载时将发生什么。简言之,是的,您加载的内容将替换已经存在的内容。这意味着如果你加载了一个扩展,以前的版本将在以前的包中被“删除”。好的,谢谢你的解释。因此,当需要在我自己的包之外的包中进行更改时,需要一些仔细的手动管理来维护这些特定的更改。例如,如果出现新版本的正则表达式,我必须记住,在升级之前,我有一个选择器的特殊版本,以保留我的版本。是的,我理解这一点。不幸的是,有几个案例