# Metaprogramming: Passing an expression as a variable

**URL:** https://discourse.julialang.org/t/metaprogramming-passing-an-expression-as-a-variable/19271
**Category:** General Usage
**Tags:** macros, metaprogramming
**Created:** [January 4, 2019, 1:38pm UTC](https://discourse.julialang.org/t/metaprogramming-passing-an-expression-as-a-variable/19271 "2019-01-04T13:38:57Z")
**Posts on this page:** 10
**Page:** 1

<div class="post-metadata">

### Author: ![Fjedor](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/fjedor/32/8075_2.png) [@Fjedor](https://discourse.julialang.org/u/Fjedor)
#### Post date: [January 4, 2019, 1:38pm UTC](https://discourse.julialang.org/t/metaprogramming-passing-an-expression-as-a-variable/19271/1 "2019-01-04T13:38:57Z")

</div>

Hey guys,

this is my first ever post on here so please don’t mind if I do something wrong.

Currently I am trying to wrap my head around macros and how to use them and what is possible and what is not. So what I want to have is a variable `expr` storing some expression and having a while loop looping over the statement stored in this variable. So a small example with a macro called `@iterate` could look like this.

```julia
expr = :(i<5)
i=0
@iterate while expr
    i += 1
    println(i)
end
1
2
3
4

```

So I had much trouble to get this working somehow. With this code I could get it to work, but I am not totally satisfied with this solution.

```julia
macro iterate(expr::Expr)
    conditions = eval(quote quote $$(expr.args[1]) end end)
    statements = expr.args[2]
    return esc(quote
            while $conditions
               $statments
            end
            end)
end

expr = :(i<5)
i=0
@iterate while expr
    global i += 1
    println(i)
end

```

So I do have some questions:

1. Does the definition of `conditions` have to be so difficult and somehow ugly?
2. I do not like the `global i +=1`. Is there a way to do this without the global?
3. Is the idea of my implementation the best one or is there an easier way to do it?

Sorry, if this is somehow trivial. I really tried to look at many threads and macro implementations, but somehow got confused on the way and only could come up with this implementation 😀.

Thanks for answers in advance and have a nice day 🙂

Fjedor

---

<div class="post-metadata">

### Author: ![mauro3](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/mauro3/32/292_2.png) [@mauro3](https://discourse.julialang.org/u/mauro3)
#### Post date: [January 4, 2019, 1:55pm UTC](https://discourse.julialang.org/t/metaprogramming-passing-an-expression-as-a-variable/19271/2 "2019-01-04T13:55:08Z")

</div>

You’re aware that you can do:

```julia
expr = :(i<5)
i=0
@eval while $expr
    global i += 1
    println(i)
end

```

? Also note that your `iterate` macro receives the symbol `:eval` and not what is in the variable. Thus you need to the the `eval` inside your macro, which is bad style. Very bad some might say.

---

<div class="post-metadata">

### Author: ![mauro3](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/mauro3/32/292_2.png) [@mauro3](https://discourse.julialang.org/u/mauro3)
#### Post date: [January 4, 2019, 2:03pm UTC](https://discourse.julialang.org/t/metaprogramming-passing-an-expression-as-a-variable/19271/3 "2019-01-04T14:03:23Z")

</div>

Most macros are probably for boiler plate like code. If you find yourself writing a lot of repetitive code you probably want a macro. The `@time` macro is a good example. You write a lot of:

```julia
julia> t0 = time_ns(); my_fn(x,y,z); Int(time_ns() - t0)

```

and you get tired. You write a macro which takes an expression and surrounds it with the timing stuff:

```julia
macro t(e)
:(t0 = time_ns(); $e; Int(time_ns() - t0))
end

julia> @t sin(4)
6214

```

---

<div class="post-metadata">

### Author: ![ffevotte](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/ffevotte/32/6587_2.png) [@ffevotte](https://discourse.julialang.org/u/ffevotte)
#### Post date: [January 4, 2019, 3:15pm UTC](https://discourse.julialang.org/t/metaprogramming-passing-an-expression-as-a-variable/19271/4 "2019-01-04T15:15:49Z")

</div>

Your macro could be rewritten like this, and have the same effect. This does not solve your concern with `global`, though.

```julia
macro iterate(expr::Expr)
    expr.args[1] = eval(expr.args[1])
    esc(expr)
end

```

You should however be aware that there are several problems with such a macro (sorry if this was already obvious to you):

- it is taylored for while loops in that it supposes that you’ll always find your variable name in `expr.args[1]`. If you call the macro with anything else, then you don’t know what will happen. You could do some pattern matching to analyze the expression that you get, check that it has the expected form, and extract from it what you want.

- more importantly, your macro works only because it is syntactically correct to put a single token (your `expr` variable) instead of a test expression (`i<5`, the contents of `expr`, which you want to substitute in the code produced by your macro). As an illustration, try to write a macro which would perform the same kind of things, but for a `for` loop. Something like this won’t work, because the parser gets confused even before it is able to call your macro:

- as already mentioned by @mauro3, using `eval` is sometimes frowned upon. That being said, I’ve sometimes done such things myself, especially when the macro takes several arguments and you want some to be unevaluated (hence the use of a macro in the first place) and others not (as if they were passed to a function). And I don’t know of any way to avoid `eval` in such cases (but maybe there exist some…)

---

<div class="post-metadata">

### Author: ![rdeits](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/rdeits/32/286_2.png) [@rdeits](https://discourse.julialang.org/u/rdeits)
#### Post date: [January 4, 2019, 3:29pm UTC](https://discourse.julialang.org/t/metaprogramming-passing-an-expression-as-a-variable/19271/5 "2019-01-04T15:29:59Z")

</div>

Yeah, I think using `eval` inside the body of a macro is almost always a bad idea. In particular, because `eval` works only at global scope, a macro which uses `eval` inside its body will either (a) error or (b) just do the wrong thing silently, depending on what global variable happen to be defined at _parse time_. That’s basically never what you want–it may work at the REPL, but you’re just asking for bugs later on.

@Fjedor what you’re trying to do isn’t possible to do in a safe way with macros. A macro takes in _code_ (specifically parsed expressions), not values, and outputs new code (more parsed expressions). Your hypothetical `@iterate` macro takes in the code `while expr ... end` and is supposed to produce code which depends on the actual _value_ of the variable `expr`. That’s just not how macros work. When you call the macro `@f(x)`, the macro `f` just receives the symbol `:x` (a tiny piece of code) and does not receive any kind of information about what _value_ some variable named `x` might have in some particular scope.

It might be easier to help you come up with a good solution if you can provide more context about the actual problem you want to solve. What’s the fundamental problem you’re trying to solve with this macro?

---

<div class="post-metadata">

### Author: ![ffevotte](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/ffevotte/32/6587_2.png) [@ffevotte](https://discourse.julialang.org/u/ffevotte)
#### Post date: [January 4, 2019, 4:19pm UTC](https://discourse.julialang.org/t/metaprogramming-passing-an-expression-as-a-variable/19271/6 "2019-01-04T16:19:52Z")

</div>

On a note related both to your second point (`global`) and the use of `eval`: because of scoping rules, your “ideal” example (i.e. without `global i`) does not work in the global scope:

```julia
julia> i=0;
julia> while i < 5
           i += 1
           println(i)
       end
ERROR: UndefVarError: i not defined
Stacktrace:
 [1] top-level scope at ./REPL[1]:2 [inlined]
 [2] top-level scope at ./none:0

```

This would work (without `global i`) in a local scope, for example in a function. But because of `eval` only working with the global scope, the macro fails during expansion if it is not used in the global scope:

```julia
julia> macro iterate(expr::Expr)
           expr.args[1] = eval(expr.args[1])
           esc(expr)
       end
@iterate (macro with 1 method)

julia> function foo()
           expr = :(i<5)
           i = 0
           @iterate while expr
               i += 1
               println(i)
           end
       end
ERROR: LoadError: UndefVarError: expr not defined
Stacktrace:
 [1] top-level scope
 [2] eval at ./boot.jl:319 [inlined]
 [3] eval(::Symbol) at ./client.jl:389
 [4] @iterate(::LineNumberNode, ::Module, ::Expr) at ./REPL[2]:2
in expression starting at REPL[3]:4

```

---

<div class="post-metadata">

### Author: ![stevengj](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/stevengj/32/71_2.png) [@stevengj](https://discourse.julialang.org/u/stevengj)
#### Post date: [January 4, 2019, 8:54pm UTC](https://discourse.julialang.org/t/metaprogramming-passing-an-expression-as-a-variable/19271/7 "2019-01-04T20:54:11Z")

</div>

> [@Fjedor](#):
>
> So what I want to have is a variable `expr` storing some expression and having a while loop looping over the statement stored in this variable.

I’m guessing you should really be passing functions around rather than expressions. For example:

```julia
function doit(f)
    i = 0
    while f(i)
        i += 1
        println(i)
    end
end

doit(i -> i < 5)

```

---

<div class="post-metadata">

### Author: ![Fjedor](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/fjedor/32/8075_2.png) [@Fjedor](https://discourse.julialang.org/u/Fjedor)
#### Post date: [January 5, 2019, 1:02pm UTC](https://discourse.julialang.org/t/metaprogramming-passing-an-expression-as-a-variable/19271/8 "2019-01-05T13:02:39Z")

</div>

Hey guys,

wow thank you for all the nice input.

@ffevotte and @mauro3 :  
Ah okay thanks for the input. Now I understand where this confusion comes from. Great! And you are right that `eval` might not be the best idea.  
I have also encounterd the problem with the `global i`. That is why I changed it and was a little afraid that I might run into problems 😃

@rdeits Yeah, I guess I have to dig into scope and stuff once again to get a better feeling and understanding of all the issues that can occur. I will give an example to explain my motivtion at the end of this post.

@stevengj  
Hm, this seems to be a solution that might work for me somehow. I will try it out later and will report if this solves my problems. This might be smarter in this way.

So just to give a little bit more insight in my motivation I will give a small example. Since I have an optimisation and algorithmic background to some extent, I wanted to implement a small algorithmic framework just for learning purpose and also wanted to play around with macros. So I thought that I might want to have a structure with an initialization, a while loop with some stopping criterion and some updates in this loop. But I wanted it to be a bit more flexible, so for example the user can tell the framework the stopping criteria like `i<10` or `abs(x-x_old)<epsilon` or a combination of such. So I thought that it might be a cool idea to do this with the `@iterate` macro as described before, since it would not distort the syntax to much, but would indicate that something different happens there. But maybe this is not the smartest idea as pointed out before.

If you have any ideas how to do this with a macro this would be fantastic. But I will try to do it as @stevengj sugggested. Maybe this works for me. 🙂

Thanks guys and have a nice weekend  
Fjedor

---

<div class="post-metadata">

### Author: ![bennedich](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/bennedich/32/4894_2.png) [@bennedich](https://discourse.julialang.org/u/bennedich)
#### Post date: [January 5, 2019, 1:37pm UTC](https://discourse.julialang.org/t/metaprogramming-passing-an-expression-as-a-variable/19271/9 "2019-01-05T13:37:21Z")

</div>

I would absolutely avoid using macros for this. I’d either simply pass arguments (could be optional keyword arguments) `max_iterations` and `tolerance` to the method, or pass a function like Steven said. Here’s how that might look like for a dummy optimization method:

```julia
function optimize(func, x, stopfunc)
    iter = 0
    yold = NaN
    while true
        y = func(x)
        delta = abs(y - yold)
        stopfunc(iter, delta) && return (x, y)
        yold = y
        iter += 1
        x += 1
    end
end

optimize(z -> 1/z, 1, (iter, delta) -> iter > 1000 || delta < 1e-5)

```

Returns:

```julia
(317, 0.0031545741324921135)

```

---

<div class="post-metadata">

### Author: ![Fjedor](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/fjedor/32/8075_2.png) [@Fjedor](https://discourse.julialang.org/u/Fjedor)
#### Post date: [January 6, 2019, 3:23pm UTC](https://discourse.julialang.org/t/metaprogramming-passing-an-expression-as-a-variable/19271/10 "2019-01-06T15:23:14Z")

</div>

Hey guys 🙂  
So I had time to test the suggestions of @stevengj and @bennedich with passing functions. This is much easier and works pretty well so thank you for this contribution 🙂 But also to all of the others. I guess I have to dig deeper in some of the topics mentioned in this thread. So thanks again and I will mark @bennedich’s post as the solution.

Fjedor
