Evaluate and capture expression result into function/closure body

Hi all,

I suddenly had a “metaphysical” doubt when learning about the @static macro.
I imagined that such macro could be used to completly evaluate a given expression and replace it by its result at compile time. It cannot.

Then I though that maybe @eval would do that. But trying

julia> a=1
julia> f() = a
julia> g() = @eval f()
julia> a=2
julia> g()
2

one can see that it wont do.

Finally, I got a way to do it through some macro like:

macro capture(expr); eval(expr); end
julia> a=1
julia> f() = a
julia> g() = @capture f()
julia> a=2
julia> g()
1

It works.

Now, I’m wondering:
Is there any uses cases for this functionality?
If yes, is there some similar macro in Base?
If not, is there another, more common, way to have this behavior?

Thanks.

You can splice in a value directly

@eval f() = $a

1 Like

But what if function f instead of returning a global variable, makes a check of the system by running some program, which one intends to be ran only once at compile time?

What do you mean by “compile time”. If it’s just a cache, then do just that. You can even write a macro to do it. If it depends on input types and by compile time you mean inference time, then it can be valid to use generated function in some cases as long as you are not calling any functions defined after this function and you can handle the case where the function is compiled multiple times.

I mean something like “parsing time” or “precompilation time”. I mean something that does not depends on future inferences of g() function due to it being called with new argument types.

But I guess I found the way this is usually done, it uses your first answer indeed but applied to the definition of g():

julia> a=1
julia> f() = a
julia> @eval g() = $(f())
julia> a=2
julia> g()
1

@eval must contain everithing since g() = @eval $(f()) does not do what I want.

I imagine that this is useful, for example, for using some constant, that is computed by a piece of Julia code, guaranteeing that such constant is computed only once, e.g.,

h(x) = x + sin(1.23)
versus

h(x) = x + @capture sin(1.23)
or
@eval h(x) = x + $(sin(1.23))

which entail different @code_llvm

Thanks

Than that’s exactly what Evaluate and capture expression result into function/closure body - #2 by yuyichao is about

Sure, I stand corrected.
(I initially tried doing g() = @eval $(f()) that’s why it didn’t work.)