How to inform object about message execution

I have an object and a string containing a message that I would like to send to it.

For example, the string '+ 5', which I would like to send to some integer object.

If it were in the workspace, I would just write "obj + 5", but I need it to be done at work, without knowing the line in advance ...

+4
source share
1 answer

If you can separate the message argument from the message itself, you can "send" the message:

obj := 3. msg := '+'. arg := 5. result := obj perform: msg asSymbol with: arg. 

Otherwise, you will have to use a compiler that translates the string into compiled code and executes it:

 obj := 3. msg := 'self + 5'. result := Compiler evaluate: msg for: obj logged: false. 

A common method to avoid recompilation is to compile a block that can be evaluated more efficiently:

 obj := 3. msg := '[:x | x + 5]'. block := Compiler evaluate: msg. result := block value: obj. 

Btw, the code above (and below) for Squeak, other Smalltalks may have a different way of accessing the compiler.

There is an even more hacker way that allows you to access a variable directly from a string. This is by executing the compiled code in "thisContext" (in this case, you need to declare temporary vars even in the workspace):

 | obj msg result | obj := 3. msg := 'obj + 5'. result := Compiler new evaluate: msg in: thisContext to: nil. 

However, I would not recommend this latest technique. Execution is usually safer than using a compiler. However, this can be used to implement some serious metafiles. For instance:.

 | obj | obj := 3. 'The result is {obj + 5}.' expand 

The implementation of the expand method remains for the curious reader;)

+12
source

Source: https://habr.com/ru/post/1410843/


All Articles