A good way to understand this method is by considering it as a syntactic variant of the general expression
object msg: arg (*)
where object is the receiver of the message with selector msg: and arg its argument. There are of course variants with no or multiple arguments, but the idea is the same.
When object receives this message (*) the Virtual Machine (VM) looks up for the CompiledMethod with selector msg: in the object's hierarchy, and transfers it the control, binding self to object and the formal argument of the method to arg.
Notice that this invocation is managed by the VM, no by the Virtual Image (VI). So, how could we reflect the same in the VI? Well, there are two steps in this behavior (1) find the method and (2) bind its formal receiver and arguments to the actual ones and let it run.
Step (1) is the so called lookup algorithm. It is easily implemented in Smalltalk: just ask the receiver its class, check whether the class includes the selector #msg: and, if not, go to the superclass and repeat. If all checks fail, issue the doesNotUnderstand: message.
Step (2) exactly requires what #withArgs:executeMethod: provides. It allows us to say
object withArgs: {arg} executeMethod: method
where method is the CompiledMethod found in step (1). [We have to use {arg} rather than arg because the plural in withArgs: suggests that the method expects an Array of arguments.]
Why would we want this?
Generally speaking, giving the VI the capability to mimic behavior implemented in the VM is good because it makes metaprogramming easier (and more natural).
More practically, a relevant example of the use of this capability is the implementation of Method Wrappers. Briefly described, given any particular method, you can wrap it (as the wrappee) inside a wrapper method, which also has a preBlock. If you then substitute the original method in the MethodDictionary where it belongs, with the wrapper, you can let the wrapper first execute the preBlock and then the intended method. The first task is easy: just send the message preBlock value. For the second we have the method (the wrappee), the receiver and the arguments (if any). So, to complete the task you only need to send to the receiver withArgs:executeMethod: with the actual argument(s) and the wrappee.
Ah! Let's not forget to mention that one of the reasons for having Method Wrappers is to measure testing coverage.
Note also that withArgs:executeMethod: does not require the second argument, i.e., the method to execute, to be in any class, let alone the class of the receiver. In particular, you could create a CompiledMethod on the fly and execute it on any given object. Of course, it is up to you to make sure that the execution will not crash the VM by, say, using the third ivar of the receiver if the receiver has only two etc. A simple way to create a CompiledMethod without installing it in any class is by asking the Smalltalk compiler to do so (look for senders of newCompiler to learn how to do that).
A good way to understand this method is by considering it as a syntactic variant of the general expression
where
objectis the receiver of the message with selectormsg:andargits argument. There are of course variants with no or multiple arguments, but the idea is the same.When
objectreceives this message (*) the Virtual Machine (VM) looks up for theCompiledMethodwith selectormsg:in theobject's hierarchy, and transfers it the control, bindingselftoobjectand the formal argument of the method toarg.Notice that this invocation is managed by the VM, no by the Virtual Image (VI). So, how could we reflect the same in the VI? Well, there are two steps in this behavior (1) find the method and (2) bind its formal receiver and arguments to the actual ones and let it run.
Step (1) is the so called lookup algorithm. It is easily implemented in Smalltalk: just ask the receiver its class, check whether the class includes the selector
#msg:and, if not, go to the superclass and repeat. If all checks fail, issue thedoesNotUnderstand:message.Step (2) exactly requires what
#withArgs:executeMethod:provides. It allows us to saywhere
methodis theCompiledMethodfound in step (1). [We have to use{arg}rather thanargbecause the plural inwithArgs:suggests that the method expects anArrayof arguments.]Why would we want this?
Generally speaking, giving the VI the capability to mimic behavior implemented in the VM is good because it makes metaprogramming easier (and more natural).
More practically, a relevant example of the use of this capability is the implementation of Method Wrappers. Briefly described, given any particular method, you can wrap it (as the
wrappee) inside awrappermethod, which also has apreBlock. If you then substitute the original method in theMethodDictionarywhere it belongs, with thewrapper, you can let thewrapperfirst execute thepreBlockand then the intended method. The first task is easy: just send the messagepreBlock value. For the second we have the method (thewrappee), the receiver and the arguments (if any). So, to complete the task you only need to send to the receiverwithArgs:executeMethod:with the actual argument(s) and thewrappee.Ah! Let's not forget to mention that one of the reasons for having Method Wrappers is to measure testing coverage.
Note also that
withArgs:executeMethod:does not require the second argument, i.e., the method to execute, to be in any class, let alone the class of the receiver. In particular, you could create aCompiledMethodon the fly and execute it on any given object. Of course, it is up to you to make sure that the execution will not crash the VM by, say, using the third ivar of the receiver if the receiver has only two etc. A simple way to create aCompiledMethodwithout installing it in any class is by asking the Smalltalk compiler to do so (look for senders ofnewCompilerto learn how to do that).