开发者

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.

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜