Reputation: 11476
Presume we have a block in the code somewhere and we assign it to a variable (either instance or local) like this.
someName := [ anInstanceVariable doThis. anotherInstanceVariable doThat.]
From the outside I would like to use it this way:
someName someMessageTheBlockDoesntImplement: argument.
Would it be possible for the block to act on the specific selector someName
and have anInstanceVariable
or anotherInstanceVariable
perform it and return those objects respectively?
PS. It would act as a kind of forwarder of sorts.
Upvotes: 2
Views: 96
Reputation: 79
The question is fairly confusing. First i guess you meant "the selector someMessageTheBlockDoesntImplement:" and not "someName". But what you are basically asking for is being able to make forwarding proxies.
You normally do not use BlockClosures to do that, instead you create a class MyForwarder which inherits either Object or even ProtoObject (depending on which Smalltalk you use and how transparent you want the forwarder to be).
Add your two instance variables in this class so that you can hold them and some method so you can set them etc.
Then you implement #doesNotUnderstand:
in MyForward which looks something like:
doesNotUnderstand: aMessage
aMessage selector == #thisMessageGoesToFirstGuy
ifTrue: [
^ firstGuy perform: aMessage selector withArguments: aMessage arguments ]
ifFalse: [
^ secondGuy perform: aMessage selector withArguments: aMessage arguments ]
Code not tested but you get the idea.
Upvotes: 4
Reputation: 511
All Smalltalk dialects allow some way to access the current context. In VisualWorks and Pharo, you use #thisContext. So if you have a method like...
Object>>someMethod
^[thisContext sender inspect] value
...send evaluate: 'abc' someMethod ... you'll get aMethodContext --> ByteString(Object)>>someMethod
or...
Object>>someMethod: aBlock
^aBlock value
'abc' someMethod: [thisContext sender inspect]
--> ByteString(Object)>>someMethod:
If you need to see more of the stack, you can use something like...
| context frames |
context := thisContext.
frames := OrderedCollection new.
[context isNil or: [context stack isNil]] whileFalse: [
frames add: context.
context := context sender].
^frames
In VA Smalltalk, you could write...
someMethod
^[Processor activeProcess currentFrame context inspect] value
...a BlockContextTemplate --> [] in Object>>#someMethod
Looking at debugger code is a good way to see what other techniques you could use.
Upvotes: 6
Reputation: 13396
You can always implement doesNotUnderstand:
of the BlockClosure
class in a way:
doesNotUnderstand: aMessage
^ self value: aMessage selector value: aMessage arguments
and then you have to have a block like this:
[ :selector :args |
^ { anInstanceVariable perform: selector withArguments: args.
anotherInstanceVariable perform: selector withArguments: args } ]
But why do you want to do something like that?
Upvotes: 3