我知道一切都是一个对象,你向Smalltalk中的对象发送消息来做几乎所有事情。
现在我们如何实现一个对象(内存表示和基本操作)来表示原始数据类型?例如,如何实现整数的+
?
我查看了Smalltalk的源代码,并在Smallint.st
中找到了它。有人可以解释这段代码吗?
+ arg [
"Sum the receiver and arg and answer another Number"
<category: 'built ins'>
<primitive: VMpr_SmallInteger_plus>
^self generality == arg generality
ifFalse: [self retrySumCoercing: arg]
ifTrue: [(LargeInteger fromInteger: self) + (LargeInteger fromInteger: arg)]
]
答案 0 :(得分:5)
从概念上讲,原始方法是由虚拟机(VM)实现的行为(例程),而不是常规的Smalltalk代码。
当Smalltalk编译器找到语句<primitive: ...>
时,它将此解释为一种特殊类型的方法,其参数(在您的情况下为VMpr_SmallInteger_plus
)表示VM中目标例程的整数索引。
在这个意义上,原语是一个全局例程,不会绑定到任何特定类的MethodDictionary
。原始逻辑用于接收器和某些类的参数,这就是为什么它必须检查接收器和参数(如果有的话)是否符合其要求的原因。如果没有,则原语失败,在这种情况下,控制将流向<primitive: ...>
语句后面的Smalltalk代码。否则原语成功并且不执行下面的Smalltalk代码。另请注意,编译器不允许在<primitive:...>
句子之外发生临时声明以外的任何Smalltalk代码。
在您的示例中,如果参数arg
不是预期的类(可能是SmallInteger
),则例程放弃尝试将其加到接收器并将操作的分辨率委托给Smalltalk代码。
如果参数恰好是SmallInteger
,则原语将计算结果(使用VM中保存的例程)并回答它。
我还没有看到这个原语的代码,但是如果和的结果不适合SmallInteger
,那么原语也会失败,在这种情况下,接收者和参数都会是转换为LargeInteger
s,添加将在相应类(#+
或LargePositiveInteger
)的LargeNegativeInteger
方法中进行。
Smalltalk代码的另一个分支允许在SmallInteger
和任何其他类型的对象之间实现多态和。例如,如果您评估3 + 4.0
,则会发生Smalltalk代码的这一部分,因为在这种情况下,参数是Float
。如果您评估3 + (4 / 3)
等等,会发生类似情况。