Smalltalk:如何实现原语?

时间:2016-09-04 21:47:34

标签: oop smalltalk

我知道一切都是一个对象,你向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)]
    ]

以上是上述代码的链接:https://github.com/gnu-smalltalk/smalltalk/blob/62dab58e5231909c7286f1e61e26c9f503b2b3df/kernel/SmallInt.st

1 个答案:

答案 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)等等,会发生类似情况。