问题
I know that everything is an object and you send messages to objects in Smalltalk to do almost everything.
Now how can we implement an object (memory representation and basic operations) to represent a primitive data type? For example how +
for integers is implemented?
I looked at the source code for Smalltalk and found this in Smallint.st
. Can someone explain this piece of code?
+ 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)]
]
Here is the link of above code: https://github.com/gnu-smalltalk/smalltalk/blob/62dab58e5231909c7286f1e61e26c9f503b2b3df/kernel/SmallInt.st
回答1:
Conceptually speaking primitive methods are pieces of behavior (routines) implemented by the Virtual Machine (VM), not by regular Smalltalk code.
When the Smalltalk compiler finds the statement <primitive: ...>
it interprets this as an special type of method whose argument (in your case VMpr_SmallInteger_plus
) indicates the integer index of the target routine within the VM.
In this sense a primitive is a global routine not bound to the MethodDictionary
of any particular class. The primitive logic is intended for a receiver and arguments of certain classes and that's why it must check that the receiver and the arguments (if any) conform its requirements. If not, the primitive fails and in that case the control flows to the Smalltalk code that follows the <primitive: ...>
statement. Otherwise the primitive succeeds and the Smalltalk code below is not executed. Note also that the compiler will not allow for any Smalltalk code other than temporary declaration occurring above the <primitive:...>
sentence.
In your example, if the argument arg
is not of the expected class (presumably a SmallInteger
) the routine gives up trying to sum it to the receiver and delegates the resolution of the operation to the Smalltalk code.
If the argument happens to be a SmallInteger
, the primitive will compute the result (using the routine held in the VM) and answer with it.
I haven't seen the code of this primitive but it could also happen that the primitive fails if the result of the sum does not fit in a SmallInteger
, in which case both the receiver and the argument would be cast to LargeInteger
s and the addition would take place in the #+
method of the appropriate class (LargePositiveInteger
or LargeNegativeInteger
).
The other branch of the Smalltalk code allows for the implementation of a polymorphic sum between a SmallInteger
and any other type of object. For instance this part of the Smalltalk code would take place if you evaluate 3 + 4.0
because in this case the argument is a Float
. Something similar happens if you evaluate 3 + (4 / 3)
, etc.
来源:https://stackoverflow.com/questions/39321776/smalltalk-how-primitives-are-implemented