背景
在Smalltalk中,如果您没有明确返回任何内容,那么传递的消息将计算为接收方(或消息上下文中的"self"(。
例如,给定这种方法:
MyClass >> myMethod
Transcript show: 'hello'; cr.
评估(不要"打印"(这个:
| myInstance |
myInstance := MyClass new.
myInstance myMethod.
如果<打印它>则结果将是实例本身。
问题
- 为什么这样设计
- 它背后的想法是什么
- 哲学背景是什么
- 它的实际好处是什么?是为了方便方法链接吗
一个非常简单的原因尚未说明:在虚拟机中,返回self比返回任何其他对象都更简单、更高效。
Smalltalk字节码实现了一个堆栈机器。这意味着参数是通过将它们推送到堆栈上而不是放入寄存器来传递的。除了方法签名中列出的参数外,还始终传递一个隐藏的参数,即消息的接收方。因此,即使对于一元方法(那些没有参数的方法(,接收器也会被推到堆栈上,然后执行该方法,堆栈上的接收器值就是该方法如何知道"self"。如果没有给出显式的返回语句,则通过返回"self",VM可以将"self-"oop留在堆栈上,从而至少保存一个内存存储操作。因此,从效率和简单性的角度来看,返回"self"是最优雅的做法。
Smalltalk-80的蓝皮书(语言及其实现(没有说明为什么默认返回receiver。
然而,第27页中有一句话("返回值">部分(可能会对您有所帮助:
"即使不需要将任何信息传达回发送方,接收方始终返回消息表达式的值。返回值表示对消息的响应已完成。(…(">
请记住,在Smalltalk中,方法是通过消息发送来激活的,因此消息有一个完整的往返行程(可能以MessageNotUnderstandtood异常结束(。消息发送的概念至关重要。
根据信息的意图,有一些很好的实践模式可以返回什么,但这是其他故事的主题。
我不是闲聊的创建者,但这似乎是最好的做法。
例如,如果您要执行:
var := myInstance myMethod.
那么问题是:你希望var
变成什么样子?一个选项是nil
。但这有点令人困惑,因为您使用的是已定义的对象,而nil
实际上是一个未定义的对象。因此,您可以将其视为将myInstance
分配给var
,并在此过程中调用myMethod。此外,这可能被视为的简写
var := myInstance myMethod; yourself.
如果你从内部看,那么从对象本身可用的所有数据来看,最合适的可能也是self
。再一次,nil
可以退货,但我之前已经告诉过我的意见。
在Smalltalk中,没有一个void方法不返回任何内容,也没有类型检查。所以一个方法只需要返回一些东西。就像对象说的:
默认情况下,我可以为任何方法调用返回自己,因为我总是了解我自己,如果你想的话,你可以重新定义这种行为我想还点别的东西。
就我个人而言,我认为返回nil
可能也很好,Objective-C应用程序经常使用nil
,但Smalltalk是这样做的,我认为这是一个很好的解决方案。
方法默认返回self,原因如下。
- Smalltalk方法必须返回一些内容
- 自我是最容易回归的对象
- self是返回速度最快的对象
- 回归自我让多种设计模式自然发挥作用
让我再解释一下#4。对象初始化的一种常见模式是为类定义一个新的方法,如下所示:
new
^super new initialize
这种模式依赖于initialize返回self。但是,在initialize方法的末尾添加^self是不正常的。这是不必要的,因为该方法无论如何都会返回self。
最后,默认情况下,返回自我只是一个自然的选择,因为你必须返回一些东西。
来自Java,您知道在处理未定义的返回值时会出现NullPointException。此外,您的代码必须在这里和那里对null进行条件检查。
因此,我很高兴在Smalltalk中为每个方法调用或消息发送找到一个返回值。如果你决定让每个方法都返回一些值,你会问你的默认值是什么。对象本身(self(是一种非常自然的方式来用作默认值。或者反过来问:什么是更好的回报价值?