On 3 March 2013 18:33, Stéphane Ducasse <[email protected]> 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.
