[Pharo-project] about method lookup
Hi I'm rethinking about my objvlisp lecture. In this lecture I'm talking about building the objVlisp kernel in Smalltalk. Now everything is working well except the error handling when a method is not found with different arguments than the original. Methods are represented with blocks having different number of arguments. I have several send messages (I should simplify this in the future) ------------------------------------------ binarySend: selector with: argument "send the message whose selector is <selector> to the receiver. The arguments of the messages are an <argument>. The method is lookep up in the class of the receiver. self is an objObject or a objClass." | ans | ans := (self objClass lookup: selector for: self) value: self value: argument. ^ ans send: selector withArguments: arguments "send the message whose selector is <selector> to the receiver. The arguments of the messages are an array <arguments>. The method is lookep up in the class of the receiver. self is an objObject or a objClass." | ans | ans := (self objClass lookup: selector for: self) valueWithArguments: (Array with: self) , arguments. ^ ans lookup is as simple as ------------------------------ lookup: selector for: anObjObject "look for the method named <selector> starting in the receiver. The lookup is done for a message sent to <anObjObject>. self is an objClass" ^(self doesUnderstand: selector) ifTrue: [ self bodyOfMethod: selector] ifFalse: [self objName = #ObjObject ifFalse: [ (Obj giveClassNamed: self objSuperclassId) lookup: selector for: anObjObject.] ifTrue: [ anObjObject objClass lookup: #error for: anObjObject]] Now the problem is that error redefinition only works if the same number of arguments are used and this is not nice. For example error redefinition works: --------------------------------------------------- testErrorRedefinition "(self run: #testErrorRedefinition)" self should: [aPoint unarySend: #zork] raise: Error. (pointClass at: pointClass offsetForMethodDict) at: #error put: ([ :superClassOfClassDefiningTheMethod | [:objself | 33]] value: objectClass). self assert: (aPoint unarySend: #zork) = 33. I could use cull: or something like that to be able to execute the block representing the error message But I have the impression that I need a way to say that the lookup failed and that the arguments should be packed in a message object. I looked in the StackVM to see how the arguments were handled: how do we go some lookupMethodInClass: class | currentClass dictionary found | ... currentClass := class. [currentClass ~= objectMemory nilObject] whileTrue: [dictionary := objectMemory fetchPointer: MethodDictionaryIndex ofObject: currentClass. ... found := self lookupMethodInDictionary: dictionary. found ifTrue: [^currentClass]. currentClass := self superclassOf: currentClass]. ... "Cound not find a normal message -- raise exception #doesNotUnderstand:" self createActualMessageTo: class. messageSelector := objectMemory splObj: SelectorDoesNotUnderstand. ^self lookupMethodInClass: class Am I correct to believe that createActualMessageTo: eats up the call args and does basically what I would like to do Stef
On 3 March 2013 18:33, Stéphane Ducasse <stephane.ducasse@inria.fr> wrote:
Hi
I'm rethinking about my objvlisp lecture. In this lecture I'm talking about building the objVlisp kernel in Smalltalk. Now everything is working well except the error handling when a method is not found with different arguments than the original. Methods are represented with blocks having different number of arguments.
I have several send messages (I should simplify this in the future) ------------------------------------------ binarySend: selector with: argument "send the message whose selector is <selector> to the receiver. The arguments of the messages are an <argument>. The method is lookep up in the class of the receiver. self is an objObject or a objClass."
| ans | ans := (self objClass lookup: selector for: self) value: self value: argument. ^ ans
send: selector withArguments: arguments "send the message whose selector is <selector> to the receiver. The arguments of the messages are an array <arguments>. The method is lookep up in the class of the receiver. self is an objObject or a objClass."
| ans | ans := (self objClass lookup: selector for: self) valueWithArguments: (Array with: self) , arguments. ^ ans
lookup is as simple as ------------------------------
lookup: selector for: anObjObject "look for the method named <selector> starting in the receiver. The lookup is done for a message sent to <anObjObject>. self is an objClass"
^(self doesUnderstand: selector) ifTrue: [ self bodyOfMethod: selector] ifFalse: [self objName = #ObjObject ifFalse: [ (Obj giveClassNamed: self objSuperclassId) lookup: selector for: anObjObject.] ifTrue: [ anObjObject objClass lookup: #error for: anObjObject]]
Now the problem is that error redefinition only works if the same number of arguments are used and this is not nice.
For example error redefinition works: --------------------------------------------------- testErrorRedefinition "(self run: #testErrorRedefinition)"
self should: [aPoint unarySend: #zork] raise: Error.
(pointClass at: pointClass offsetForMethodDict) at: #error put: ([ :superClassOfClassDefiningTheMethod | [:objself | 33]] value: objectClass).
self assert: (aPoint unarySend: #zork) = 33.
I could use cull: or something like that to be able to execute the block representing the error message But I have the impression that I need a way to say that the lookup failed and that the arguments should be packed in a message object.
I looked in the StackVM to see how the arguments were handled: how do we go some
lookupMethodInClass: class | currentClass dictionary found | ... currentClass := class. [currentClass ~= objectMemory nilObject] whileTrue: [dictionary := objectMemory fetchPointer: MethodDictionaryIndex ofObject: currentClass. ... found := self lookupMethodInDictionary: dictionary. found ifTrue: [^currentClass]. currentClass := self superclassOf: currentClass]. ...
"Cound not find a normal message -- raise exception #doesNotUnderstand:" self createActualMessageTo: class. messageSelector := objectMemory splObj: SelectorDoesNotUnderstand. ^self lookupMethodInClass: class
Am I correct to believe that createActualMessageTo: eats up the call args and does basically what I would like to do
yes. On DNU, an original message is replaced with #doesNotUnderstand: as selector and Message instance, which contains original message (the receiver is unchanged). Next, VM again does a lookup for #doesNotUnderstand: and here is caveat: if object does not understands #doesNotUnderstand: there is no way how you can proceed, so execution should fail with some error.
Stef
-- Best regards, Igor Stasenko.
participants (2)
-
Igor Stasenko -
Stéphane Ducasse