我知道一切都是一个对象,你向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)]
]
Run Code Online (Sandbox Code Playgroud)
以下是上述代码的链接:https://github.com/gnu-smalltalk/smalltalk/blob/62dab58e5231909c7286f1e61e26c9f503b2b3df/kernel/SmallInt.st
从概念上讲,原始方法是由虚拟机(VM)实现的行为(例程),而不是常规的Smalltalk代码.
当Smalltalk编译器找到该语句时,<primitive: ...>它将其解释为一种特殊类型的方法,其参数(在您的情况下VMpr_SmallInteger_plus)表示VM中目标例程的整数索引.
在这个意义上,原语是一个不受MethodDictionary任何特定类约束的全局例程.原始逻辑用于接收器和某些类的参数,这就是为什么它必须检查接收器和参数(如果有的话)是否符合其要求的原因.如果不是,则原语失败,在这种情况下,控制流向<primitive: ...>语句后面的Smalltalk代码.否则原语成功,并且不执行下面的Smalltalk代码.另请注意,编译器不允许除<primitive:...>句子上方的临时声明之外的任何Smalltalk代码.
在您的示例中,如果参数arg不是预期的类(可能是a SmallInteger),则例程放弃尝试将其加到接收器并将操作的分辨率委托给Smalltalk代码.
如果参数恰好是a SmallInteger,则原语将计算结果(使用VM中保存的例程)并回答它.
我还没有看到这个原语的代码,但是如果sum的结果不适合a SmallInteger,那么原语也会失败,在这种情况下,接收者和参数都会被强制转换为LargeIntegers并且加法需要放在#+适当的类(LargePositiveInteger或LargeNegativeInteger)的方法中.
Smalltalk代码的另一个分支允许在a SmallInteger和任何其他类型的对象之间实现多态和.例如,如果您评估,那么Smalltalk代码的这一部分将会发生,3 + 4.0因为在这种情况下参数是a Float.如果您评估3 + (4 / 3)等等,会发生类似情况.