# Metaprogramming/code generation inside a function

**URL:** <https://discourse.julialang.org/t/metaprogramming-code-generation-inside-a-function/5821>\
**Category:** General Usage\
**Tags:** metaprogramming\
**Created:** [September 11, 2017, 12:23pm UTC](https://discourse.julialang.org/t/metaprogramming-code-generation-inside-a-function/5821 "2017-09-11T12:23:15Z")\
**Posts on this page:** 11\
**Page:** 1

<div class="post-metadata">

**Author:** ![louisponet](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/louisponet/32/2070_2.png) [@louisponet](https://discourse.julialang.org/u/louisponet)\
**Post date:** [September 11, 2017, 12:23pm UTC](https://discourse.julialang.org/t/metaprogramming-code-generation-inside-a-function/5821/1 "2017-09-11T12:23:15Z")

</div>

Hi,

First I’ll quickly sketch the goal:  
I’ve been trying to read an input file which has a couple of blocks (control,system,electrons,ions,cell). Each block starts with a & and ends with a /. Inside each block there are several keywords and values. For each of these blocks I want to create a dictionary and store the key-value pairs.

Now, since the loop inside each block is exactly the same, I thought this would a perfect opportunity to get some metaprogramming/code generation in there.

I’ve been experimenting with stuff to try and get this to work, but I can’t seem to figure out just how exactly do it. I’ve looked at the documentation and other resources on this, but I don’t fully get how code inside function declarations gets parsed.

The code looks like this:

```julia
function read_QEInput(filename,T=Float32)
  blocks = [:control,:system,:electrons,:ions,:cell] 
  :($(block...) = [Dict{Symbol,Any}() for i=1:5])
  open(filename) do f
    while !eof(f)
      line = readline(f)
      for block in blocks
        if contains(line,"&$(Symbol(block))")
          line = readline(f)
          while !contains(line,"/")
            if contains(line,"!")
              line = readline(f)
              continue
            end
            split_line = filter(x->x!="",strip.(split(line,",")))
            for s in split_line
              key,val = String.(strip.(split(s,"=")))
              :($block[Symbol(key)] = isnull(tryparse(T,val)) ? val : get(tryparse(T,val)))
            end
            line = readline(f)
          end
        end
      end
    end
  end
  return control,system,electrons,ions,cell
end 

```

What I’m trying to accomplish is first to initiate the dictionaries, basically to get to an expression like this:  
`control,system,electrons,ions,cell = [Dict{Symbol,Any} for i=1:5]` ,  
then to basically generate an `if contains(line,"&block")` section for each of the blocks that I define.

However none of my tries amounted to anything that actually worked. So I guess my questions are: am I trying to do something that is impossible? Am I approaching it from the wrong angle?

I know I could just define another function or maybe a macro which handles this block of code, but I think it would be more clear like this + it might be instructive to learn about the workings of the language.

Thanks!

---

<div class="post-metadata">

**Author:** ![antoine-levitt](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/antoine-levitt/32/4008_2.png) [@antoine-levitt](https://discourse.julialang.org/u/antoine-levitt)\
**Post date:** [September 11, 2017, 12:41pm UTC](https://discourse.julialang.org/t/metaprogramming-code-generation-inside-a-function/5821/2 "2017-09-11T12:41:51Z")

</div>

Not sure if that’s what you want or if it’s the recommended way to do it, but have you tried looking into `@eval`?

(also, if you are writing a parser for Quantum Espresso input files, please put the code online somewhere! :-))

---

<div class="post-metadata">

**Author:** ![yuyichao](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/yuyichao/32/20_2.png) [@yuyichao](https://discourse.julialang.org/u/yuyichao)\
**Post date:** [September 11, 2017, 12:45pm UTC](https://discourse.julialang.org/t/metaprogramming-code-generation-inside-a-function/5821/3 "2017-09-11T12:45:26Z")

</div>

> [@antoine-levitt](#):
>
> Not sure if that’s what you want or if it’s the recommended way to do it, but have you tried looking into @eval?

Don’t do that…

> [@louisponet](#):
>
> Now, since the loop inside each block is exactly the same, I thought this would a perfect opportunity to get some metaprogramming/code generation in there.

No, what you have there seems like normal loop, you don’t need and shouldn’t use any meta-programming “inside the function” here.

---

<div class="post-metadata">

**Author:** ![louisponet](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/louisponet/32/2070_2.png) [@louisponet](https://discourse.julialang.org/u/louisponet)\
**Post date:** [September 11, 2017, 12:50pm UTC](https://discourse.julialang.org/t/metaprogramming-code-generation-inside-a-function/5821/4 "2017-09-11T12:50:54Z")

</div>

Yes, I thought that as well. But then could you elaborate on how to assign Dicts to each of the variables (the ones in blocks are supposed to be the variables)?  
This obviously doesn’t work:

```julia
blocks... = [Dict{Symbol,Any}() for i=1:5]

```

neither do variations on that construct.

Also if i recall correctly I get an error in setindex!(:Symbol,:Symbol,:String/:Any) in the body of the for block in blocks loop.

---

<div class="post-metadata">

**Author:** ![louisponet](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/louisponet/32/2070_2.png) [@louisponet](https://discourse.julialang.org/u/louisponet)\
**Post date:** [September 11, 2017, 12:56pm UTC](https://discourse.julialang.org/t/metaprogramming-code-generation-inside-a-function/5821/5 "2017-09-11T12:56:39Z")

</div>

I tried that, putting the blocks=[…] outside the function and then @eval. But that results in a block is undefined issue for some reason.

---

<div class="post-metadata">

**Author:** ![yuyichao](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/yuyichao/32/20_2.png) [@yuyichao](https://discourse.julialang.org/u/yuyichao)\
**Post date:** [September 11, 2017, 12:56pm UTC](https://discourse.julialang.org/t/metaprogramming-code-generation-inside-a-function/5821/6 "2017-09-11T12:56:47Z")

</div>

> [@louisponet](#):
>
> But then could you elaborate on how to assign Dicts to each of the variables (the ones in blocks are supposed to be the variables)?

You can’t. If the variable names are fixed, just write them out, if they are not fixed, then just use a dict to store them instead. i.e. `Dict{Symbol,Dict{Symbol,Any}}` (Also you can just use string since that’s what you get from parsing).

> [@louisponet](#):
>
> setindex!(:Symbol,:Symbol,:String/:Any)

And similarly, this is impossible by design.

---

<div class="post-metadata">

**Author:** ![louisponet](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/louisponet/32/2070_2.png) [@louisponet](https://discourse.julialang.org/u/louisponet)\
**Post date:** [September 11, 2017, 1:03pm UTC](https://discourse.julialang.org/t/metaprogramming-code-generation-inside-a-function/5821/7 "2017-09-11T13:03:04Z")

</div>

> [@yuyichao](#):
>
> setindex!(:Symbol,:Symbol,:String/:Any)
> 
> And similarly, this is impossible by design.

This is what I expected as well. So what I am trying to do inside of the block in blocks loop is impossible (interpreting the Symbol as a variable rather than the symbol)?

---

<div class="post-metadata">

**Author:** ![tshort](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/tshort/32/43_2.png) [@tshort](https://discourse.julialang.org/u/tshort)\
**Post date:** [September 11, 2017, 1:22pm UTC](https://discourse.julialang.org/t/metaprogramming-code-generation-inside-a-function/5821/8 "2017-09-11T13:22:47Z")

</div>

I’d go with one of your original options of defining another function to do the core part. Something like the following:

```julia
function read_QEInput(filename,T=Float32)
  open(filename) do f
    return (read_block(f, "control", T),
            read_block(f, "system", T),
            read_block(f, "electrons", T),
            read_block(f, "ions", T),
            read_block(f, "cell", T))
  end
end

```

---

<div class="post-metadata">

**Author:** ![louisponet](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/louisponet/32/2070_2.png) [@louisponet](https://discourse.julialang.org/u/louisponet)\
**Post date:** [September 11, 2017, 1:29pm UTC](https://discourse.julialang.org/t/metaprogramming-code-generation-inside-a-function/5821/9 "2017-09-11T13:29:11Z")

</div>

Ok, thanks! So with regards to the uses of metaprogramming in these situations to generate code. Is it correct for me to think about it as to only use it to generate code that is evaluated in global scope, but not really for copy pasting code inside function bodies? For example, i’ve used it to define multiple functions that had the same general structure but slightly altered parts in the body, this worked well with the @eval macro + pushing the code into `quote end` blocks which then got pasted later.

---

<div class="post-metadata">

**Author:** ![yuyichao](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/yuyichao/32/20_2.png) [@yuyichao](https://discourse.julialang.org/u/yuyichao)\
**Post date:** [September 11, 2017, 1:46pm UTC](https://discourse.julialang.org/t/metaprogramming-code-generation-inside-a-function/5821/10 "2017-09-11T13:46:57Z")

</div>

> [@louisponet](#):
>
> So what I am trying to do inside of the block in blocks loop is impossible (interpreting the Symbol as a variable rather than the symbol)?

Correct.

> [@louisponet](#):
>
> Is it correct for me to think about it as to only use it to generate code that is evaluated in global scope, but not really for copy pasting code inside function bodies?

No. You can use a macro for that, as long as the information you need to generate the code is available from just syntactic information (at compile time). Generating code is a compile time operation so it is by definition impossible to do with only runtime features.

---

<div class="post-metadata">

**Author:** ![louisponet](https://sea2.discourse-cdn.com/julialang/user_avatar/discourse.julialang.org/louisponet/32/2070_2.png) [@louisponet](https://discourse.julialang.org/u/louisponet)\
**Post date:** [September 11, 2017, 1:49pm UTC](https://discourse.julialang.org/t/metaprogramming-code-generation-inside-a-function/5821/11 "2017-09-11T13:49:24Z")

</div>

> [@yuyichao](#):
>
> No. You can use a macro for that, as long as the information you need to generate the code is available from just syntactic information (at compile time). Generating code is a compile time operation so it is by definition impossible to do with only runtime features.

Ok, seems logical. Thanks for the clarification!
