Question

y:=3. z:=4.
h:= '[x:= y+z.]'.
(BlockClosure readFromString: h) value.

I have this code where I am trying to take a string in smalltalk syntax and trying to put it in a block and executing it but I am getting an error which says :
Unhandled Exception: Message not understood #+

When I do comething like
h:= '[x:= 3+4.]'.
(BlockClosure readFromString: h) value

it works just fine. I don't understand why this is happening. I am guessing y is not pointing to anything and it does not understand the + method. But why is the block not treating y and z as free variables?

Was it helpful?

Solution

Your problem is that y and z are not known in the context that actually compiles the string into a block. You'd probably be better off with something like this:

h := '[ :y :z | x := y + z]'.
(BlockClosure readFromString: h) value: 3 value: 4.

Although I suspect that code probably won't work either - because x hasn't been declared anywhere, so a more correct version would be:

h := '[ :y :z | y + z]'.
x := (BlockClosure readFromString: h) value: 3 value: 4.

I don't think there's any real way you can make a String representation of a block act like a true closure in the context it's parsed, since it just won't have access to the variables - and would fail to compile.

OTHER TIPS

If you really really need to do this, try the following:

   | x y z h block |
   y:=3. z:=4.
   h:= '[x:= y+z.]'.

   block := Compiler new
      evaluate: h
      in: thisContext
      allowReceiver: true
      receiver: self
      environment: self class environment
      notifying: nil
      ifFail: [self error: 'Failed to compile'].

   ^block value

I'd recommend, however, that you find a nicer way to solve the problem. Dynamically compiling strings in the context of a running method is really tricky and could be brittle.

James Robertson recently posted to his blog regarding Dynamic Code Generation. You may find it useful.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top