为什么Smalltalk中的方法默认返回“self”?

15

背景

在Smalltalk中,如果您没有显式返回任何内容,则消息传递将评估为接收者(或消息上下文中的"self")。

例如,给定此方法:

MyClass >> myMethod
  Transcript show: 'hello'; cr.

执行(doint "print-it")命令的结果是:

| myInstance |
myInstance := MyClass new.
myInstance myMethod.

如果对最后的调用执行 <print-it> 操作,那么结果将是该实例本身。

问题

  • 为什么会这样设计?
  • 背后的想法是什么?
  • 哲学背景是什么?
  • 它有什么实际好处?是为了方便方法链编程吗?

3
相关话题的一个有趣注记:代码块返回最后一个表达式的结果。 - Lukas Renggli
5个回答

18

还有一个非常简单的原因没有被提到:在虚拟机中,返回self比返回任何其他对象更简单、更有效。

Smalltalk字节码实现了堆栈机。这意味着参数是通过将它们推入堆栈中来传递的,而不是将它们放入寄存器中。除了方法签名中列出的参数之外,总有一个隐藏的参数被传递,这就是消息的接收者。所以即使对于无参方法(那些没有参数的方法),接收者也会被推入堆栈,然后执行方法,堆栈上的接收者值就是方法知道“self”的方式。如果没有明确的返回语句,则通过返回"self",虚拟机可以将"self"oop留在堆栈上,这样至少可以节省一次内存存储操作。因此,从效率和简洁性的角度来看,返回"self"是最优雅的做法。


1
我的直觉是你做得很好。这听起来就像是Smalltalk-80原始实现中所发现的优化的类型。 - akuhn

8
Smalltalk-80的《蓝皮书》(The Language and its Implementation)没有解释为什么默认情况下返回接收者。不过在第27页("Returning values")中有一句话可能会对你有所帮助:

"即使不需要向发送者传递任何信息,接收者总是返回消息表达式的值。返回值表示对消息的响应已经完成。(...)"

请记住,在Smalltalk中,方法通过消息发送来激活,因此一个消息有一个完整的往返过程(可能会以MessageNotUnderstood异常结束)。消息发送的概念非常重要。
根据消息的意图,有一些良好的实践模式可以确定返回什么内容,但这是另一个故事的主题。

6

方法默认返回self,有几个原因:

  1. Smalltalk方法必须返回某些内容
  2. self是最容易返回的对象
  3. self是最快返回的对象
  4. 返回self可以自然地使用几种设计模式

让我更详细地解释一下第四点。对象初始化的一种常见模式是为类定义一个new方法,该方法看起来像这样:

new
   ^super new initialize

该模式依赖于initialize返回self。然而,在initialize方法末尾添加^self并不常见。因为该方法本身就会返回self,所以这样做是不必要的。
从根本上讲,由于必须返回某些内容,返回self只是一个默认的自然选择。

是的,返回 self 可以帮助“链式”传递消息。这个想法在一些 Java 方法中也可以找到。 - U. Windl

6

我并非Smalltalk的创始人,但它似乎是最好的选择。

例如,如果您执行以下操作:

var := myInstance myMethod.

那么问题来了:你希望var变成什么?其中一种选择是nil。但这有点令人困惑,因为你正在使用已定义的对象,而nil实际上是未定义的对象。所以你可以把它看作是将myInstance赋值给var,并沿途调用myMethod。也可以将其视为缩写形式。

 var := myInstance myMethod; yourself.

如果从内部来看,那么对于对象本身可用的所有数据而言,最合适的可能也是self。再次说明,nil可以被返回,但我之前已经表达了我的观点。
在Smalltalk中,没有返回空值的void方法,也没有类型检查。因此,一个方法必须返回某种东西。就像对象说的:

我默认可以通过返回自己来响应任何方法调用,因为我总是知道自己的情况,如果您想让我返回其他内容,您可以重新定义这种行为。

个人认为返回nil也可能很好,Objective-C应用程序经常使用nil,但Smalltalk是这样设计的,我认为这是一个相当不错的解决方案。

0

如果你熟悉Java,你就知道在处理未定义的返回值时会出现NullPointExceptions。此外,你的代码必须在这里和那里进行空值条件检查。

因此,我很高兴在Smalltalk中找到了每个方法调用或消息发送的返回值。如果你决定让每个方法都返回一些值,你可能会问默认值是什么。对象本身(self)是一种非常自然的默认值使用方式。或者换句话说:有什么更好的返回值呢?


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