Example 1 – Making a new expression

Let's start with a simple one. Suppose that we want to create a macro called @squared that takes an expression and just squares it. In other words, if we run @squared(x), then it should be translated into x * x:

macro squared(ex)
return :($(ex) * $(ex))
end

At first glance, it seems to work fine when we run it from the REPL:

But this macro has a problem with the execution context. The best way to illustrate the problem is by defining a function that uses the macro. So let's define a foo function, as follows:

function foo()
x = 2
return @squared x
end

Now, when we call the function, we get the following error:

Why is that? It is because, during the macro expansion, the x symbol refers to the variable in the module rather than the local variable in the foo function. We can confirm this by using the @code_lowered macro:

Obviously, our intention was to square the local x variable rather than Main.x. The easy fix to this problem is to use the esc function during interpolation in order to place the expression directly in the syntax tree without letting the compiler resolve it. The following is how it can be done:

macro squared(ex)
return :($(esc(ex)) * $(esc(ex)))
end

Since the macro was expanded earlier, before foo was defined, we need to define the foo function once again, as follows, for this updated macro to take effect. Alternatively, you can start a new REPL and define the @squared macro and foo function again. Here we go:

The foo function works correctly now. 

From this example, we have learned how to create a new expression using the interpolation technique. We have also learned that the interpolated variable needs to be escaped using the esc function to avoid it being resolved by the compiler to the global scope.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
18.119.139.50