链接关键字消息

Chaining keyword messages

假设我有一个对象 x,它可以接受选择器 s1s2、...、sn 中的任何一个。让我们进一步假设这些选择器中的任何一个对对象进行操作的结果是相同类型的更新对象。然后我可以 "chain" 这些选择器(只要它们是 一元消息 ),如我所愿,例如:

x s1 s2 ... sn

这将获取 x s1 的结果并应用选择器 s2,然后将选择器 s3 应用于该结果,依此类推。我想按某种顺序应用这些选择器中的一个或多个以获得各种结果:

x s8 s2

在 Smalltalk 中,如果选择器是一元消息,我可以这样做。但是,如果我的选择器是关键字消息,我就不能再这样做了。如果 x 单独接受选择器 s1:s2:、...、sn:,则以下内容不起作用:

x s1: a1 s2: a2 ... sn: an

;运算符:

x s1: a1 ; s2: a2 ; ... ; sn: an

但是使用级联:每个阶段都会沿途修改原始x,在这种情况下我不希望修改x

要链接关键字消息,我想我只能使用以下带括号的语法:

(...(((x s1: a1) s2: a2) ... sn: an)

如果我有 3 个或更多的关键字消息,这让我觉得我在用 LISP 编程。一个具体的例子就是多维数组。如果 foo 是一个 3 维数组,并且您想访问数组中位置 2,3,5 的对象,我认为它看起来像:

(((foo at: 2) at: 3) at: 5) some_object_selectors

当然,这是一个微不足道的例子,但可以说明情况。可能有其他类型的嵌入对象,或您对最终结果感兴趣的其他连续对象操作链。

在 Smalltalk 中是否有一种语法上更吸引人的方式来做到这一点?我假设没有另一个运算符,可能是 ; 运算符的表亲(比如我们使用 &),它会链接它们,例如:

x s1: a1 & s2: a2 & ... & sn: an

由于我想以任何或几乎任何所需的顺序应用选择器(对于可能不同的结果),选择器形式 s1:s2:s3:... 过于局限。此外,这提供了其他语言中已经存在的便利,例如 Ruby,它可以等效地表示为:

x.s1(a1).s2(a2)...sn(an)

缺少特殊运算符,替代方法可能是传递选择器-参数对数组,或者可能是选择器-参数对的查找 table。查找 table 需要设置传递文字(必须创建和填充它),这让我倾向于数组,因为我可以简单地将其写为:

x { {s1. a1}. {s2. a2}. ... {sn. an} }

这仍然有点笨拙,而且我不确定这是否比仅使用所有括号更优雅。恐怕我的问题可能至少部分是主观的,但我很想知道最佳实践可能是什么,以及是否存在一个我不知道哪个可能有帮助的操作员,或者一个人是否正在接受 Smalltalk 的娱乐标准机构。

通常我们给这个对象 x 一个主题来操作,然后在我们完成它时请求这个改变的主题。复制效率很低

Object subclass: #Foo
    instanceVariableNames: 'subject'
    classVariableNames: ''
    poolDictionaries: ''
    category: 'Try'

order: y
    self subject order: y

select: z
    self subject select: z

subject
    ^subject ifNil: [ subject := FooSubject new ]

where: x
    self subject where: x

这里好像有点乱。

  1. 级联 使用 ; 完成,其中每条消息都发送到相同的参数。
  2. 您的 x s1 s2... 示例(您称为 "cascading")称为 消息链 ,其中每条消息都发送到前一条消息的结果(由于 Smalltalk 语法的美丽和优雅的本质,它只是 Object message 并且总是 returns 结果)。不,你不能总是把它们放在任何顺序。想象一下 s1multiplyByTwos2addTwox 有一个实例变量被这些方法修改为 1。顺序可能很重要。 (请注意,我非常不愿意使用如此短的名称作为示例 - 它不是很像 Smalltalk。;-)
  3. 如果您的 n 太大以至于使用括号会使它看起来很尴尬,那么,嗯...抱歉,您做错了。
    • 考虑在您的对象上创建一个方法来接受多个参数。
    • 考虑创建一个包装器对象来携带您的参数。
    • 考虑使用设计模式将对象与要对其执行的操作分离。 (您需要哪种模式将取决于您想要实现的目标;here's a good starting point。)

与其寻找操作员让 Smalltalk 屈服于您的意愿(您可能习惯于用其他语言做事),我建议您屈服于 Smalltalk 的意愿(明确命名,不要害怕创建更多的对象和方法等)。从长远来看,您会从中获益更多 运行,我敢说您会达到希望其他语言拥有 Smalltalk 的简单性和强大功能的地步。