Modifying the contents of a closure
Is there a better way to do it than:
|aBlock|
aBlock := [3+2].
aBlock := Object readFrom: (a printString copyReplaceAll: '3' with: '2').
?
EDIT This code was just an example, w开发者_开发百科hat about things like:
[:something |
something checkSomethingElse ifNil:
[whatever]
ifNotNil:
[something getSomethingDone]]
Where now I want to checkAnotherThing instead of checkSomethingElse.
or:
[:oneParameter :anotherParameter |
oneParameter doSomethingWith: anotherParameter]
Where now I want to add a third parameter and:
[:oneParameter :anotherParameter :yetAnotherParameter |
oneParameter doSomethingWith: anotherParameter and: yetAnotherParameter]
Serialising a Block as a string and doing string manipulations, while handy, is also quite dangerous if you don't have a very clear idea of the contents of the Block.
It sounds like you'd like to be able to manipulate the AST of the block - given a block, parse it, change the structure (replacing the literal, in this case) and then compile the changed structure. To that end, you could do something like this:
| aBlock ast |
aBlock := [3+2].
ast := aBlock decompile.
ast statements first receiver: (DecompilerConstructor new codeAnyLiteral: 4).
aBlock := (Compiler evaluate: ast printString) first.
aBlock value. "==> 6"
Note that we're not actually altering aBlock, but creating a mutated copy of aBlock.
The principle applies more generally: decompile the block, do your manipulation (changing the selector halfway through a chain of message sends, for instance), compile the new parse tree. (I don't know off-hand how to compile the tree directly rather than evaluating the printed out tree, but I'm sure there's a way.)
(Caveat: I've written the above in Squeak. I don't know the state of play with Opal, Pharo's new compiler, so perhaps you'd do something slightly different in Pharo.)
In Pharo:
| aBlock x |
x := 1.
aBlock := [ x := x + 1].
Transcript show: aBlock value printString; cr.
x := 41.
Transcript show: aBlock value printString; cr.
Of course you can use reflection to manipulate blocks, but the cleanest solution is to dynamically bind values in your block by wrapping it with another block:
factory := [ :a :b | [ a + b ] ].
The factory
produces blocks where a and b are bound to different values:
aBlock := factory value: 3 value: 2.
Evaluating aBlock
answers 5
.
精彩评论